@nativesquare/soma 0.8.0 → 0.9.1

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.
Files changed (530) hide show
  1. package/dist/client/index.d.ts +7 -128
  2. package/dist/client/index.d.ts.map +1 -1
  3. package/dist/client/index.js +31 -112
  4. package/dist/client/index.js.map +1 -1
  5. package/dist/component/_generated/api.d.ts +98 -4
  6. package/dist/component/_generated/api.d.ts.map +1 -1
  7. package/dist/component/_generated/api.js.map +1 -1
  8. package/dist/component/_generated/component.d.ts +136 -261
  9. package/dist/component/_generated/component.d.ts.map +1 -1
  10. package/dist/{garmin → component/garmin}/auth.d.ts +8 -1
  11. package/dist/component/garmin/auth.d.ts.map +1 -0
  12. package/dist/component/garmin/auth.js.map +1 -0
  13. package/dist/component/garmin/client.d.ts +15 -0
  14. package/dist/component/garmin/client.d.ts.map +1 -0
  15. package/dist/component/garmin/client.js +32 -0
  16. package/dist/component/garmin/client.js.map +1 -0
  17. package/dist/component/garmin/private.d.ts +543 -0
  18. package/dist/component/garmin/private.d.ts.map +1 -0
  19. package/dist/component/garmin/private.js +1461 -0
  20. package/dist/component/garmin/private.js.map +1 -0
  21. package/dist/component/garmin/public.d.ts +149 -0
  22. package/dist/component/garmin/public.d.ts.map +1 -0
  23. package/dist/component/garmin/public.js +823 -0
  24. package/dist/component/garmin/public.js.map +1 -0
  25. package/dist/component/garmin/schemas/activity.d.ts +94 -0
  26. package/dist/component/garmin/schemas/activity.d.ts.map +1 -0
  27. package/dist/component/garmin/schemas/activity.js +29 -0
  28. package/dist/component/garmin/schemas/activity.js.map +1 -0
  29. package/dist/component/garmin/schemas/activityDetails.d.ts +146 -0
  30. package/dist/component/garmin/schemas/activityDetails.d.ts.map +1 -0
  31. package/dist/component/garmin/schemas/activityDetails.js +30 -0
  32. package/dist/component/garmin/schemas/activityDetails.js.map +1 -0
  33. package/dist/component/garmin/schemas/bloodPressure.d.ts +38 -0
  34. package/dist/component/garmin/schemas/bloodPressure.d.ts.map +1 -0
  35. package/dist/component/garmin/schemas/bloodPressure.js +27 -0
  36. package/dist/component/garmin/schemas/bloodPressure.js.map +1 -0
  37. package/dist/component/garmin/schemas/bodyCompositions.d.ts +42 -0
  38. package/dist/component/garmin/schemas/bodyCompositions.d.ts.map +1 -0
  39. package/dist/component/garmin/schemas/bodyCompositions.js +27 -0
  40. package/dist/component/garmin/schemas/bodyCompositions.js.map +1 -0
  41. package/dist/component/garmin/schemas/dailies.d.ts +98 -0
  42. package/dist/component/garmin/schemas/dailies.d.ts.map +1 -0
  43. package/dist/component/garmin/schemas/dailies.js +27 -0
  44. package/dist/component/garmin/schemas/dailies.js.map +1 -0
  45. package/dist/component/garmin/schemas/epochs.d.ts +54 -0
  46. package/dist/component/garmin/schemas/epochs.d.ts.map +1 -0
  47. package/dist/component/garmin/schemas/epochs.js +27 -0
  48. package/dist/component/garmin/schemas/epochs.js.map +1 -0
  49. package/dist/component/garmin/schemas/healthSnapshot.d.ts +48 -0
  50. package/dist/component/garmin/schemas/healthSnapshot.d.ts.map +1 -0
  51. package/dist/component/garmin/schemas/healthSnapshot.js +27 -0
  52. package/dist/component/garmin/schemas/healthSnapshot.js.map +1 -0
  53. package/dist/component/garmin/schemas/hrvSummary.d.ts +40 -0
  54. package/dist/component/garmin/schemas/hrvSummary.d.ts.map +1 -0
  55. package/dist/component/garmin/schemas/hrvSummary.js +27 -0
  56. package/dist/component/garmin/schemas/hrvSummary.js.map +1 -0
  57. package/dist/component/garmin/schemas/manuallyUpdatedActivities.d.ts +94 -0
  58. package/dist/component/garmin/schemas/manuallyUpdatedActivities.d.ts.map +1 -0
  59. package/dist/component/garmin/schemas/manuallyUpdatedActivities.js +29 -0
  60. package/dist/component/garmin/schemas/manuallyUpdatedActivities.js.map +1 -0
  61. package/dist/component/garmin/schemas/menstrualCycleTracking.d.ts +100 -0
  62. package/dist/component/garmin/schemas/menstrualCycleTracking.d.ts.map +1 -0
  63. package/dist/component/garmin/schemas/menstrualCycleTracking.js +28 -0
  64. package/dist/component/garmin/schemas/menstrualCycleTracking.js.map +1 -0
  65. package/dist/component/garmin/schemas/moveIQ.d.ts +40 -0
  66. package/dist/component/garmin/schemas/moveIQ.d.ts.map +1 -0
  67. package/dist/component/garmin/schemas/moveIQ.js +27 -0
  68. package/dist/component/garmin/schemas/moveIQ.js.map +1 -0
  69. package/dist/component/garmin/schemas/pulseOx.d.ts +38 -0
  70. package/dist/component/garmin/schemas/pulseOx.d.ts.map +1 -0
  71. package/dist/component/garmin/schemas/pulseOx.js +28 -0
  72. package/dist/component/garmin/schemas/pulseOx.js.map +1 -0
  73. package/dist/component/garmin/schemas/respiration.d.ts +34 -0
  74. package/dist/component/garmin/schemas/respiration.d.ts.map +1 -0
  75. package/dist/component/garmin/schemas/respiration.js +28 -0
  76. package/dist/component/garmin/schemas/respiration.js.map +1 -0
  77. package/dist/component/garmin/schemas/skinTemperature.d.ts +36 -0
  78. package/dist/component/garmin/schemas/skinTemperature.d.ts.map +1 -0
  79. package/dist/component/garmin/schemas/skinTemperature.js +28 -0
  80. package/dist/component/garmin/schemas/skinTemperature.js.map +1 -0
  81. package/dist/component/garmin/schemas/sleeps.d.ts +88 -0
  82. package/dist/component/garmin/schemas/sleeps.d.ts.map +1 -0
  83. package/dist/component/garmin/schemas/sleeps.js +27 -0
  84. package/dist/component/garmin/schemas/sleeps.js.map +1 -0
  85. package/dist/component/garmin/schemas/stress.d.ts +70 -0
  86. package/dist/component/garmin/schemas/stress.d.ts.map +1 -0
  87. package/dist/component/garmin/schemas/stress.js +30 -0
  88. package/dist/component/garmin/schemas/stress.js.map +1 -0
  89. package/dist/component/garmin/schemas/userMetrics.d.ts +36 -0
  90. package/dist/component/garmin/schemas/userMetrics.d.ts.map +1 -0
  91. package/dist/component/garmin/schemas/userMetrics.js +28 -0
  92. package/dist/component/garmin/schemas/userMetrics.js.map +1 -0
  93. package/dist/component/garmin/transform/activity.d.ts +13 -0
  94. package/dist/component/garmin/transform/activity.d.ts.map +1 -0
  95. package/dist/component/garmin/transform/activity.js +111 -0
  96. package/dist/component/garmin/transform/activity.js.map +1 -0
  97. package/dist/component/garmin/transform/activityDetails.d.ts +13 -0
  98. package/dist/component/garmin/transform/activityDetails.d.ts.map +1 -0
  99. package/dist/component/garmin/transform/activityDetails.js +173 -0
  100. package/dist/component/garmin/transform/activityDetails.js.map +1 -0
  101. package/dist/component/garmin/transform/bloodPressure.d.ts +12 -0
  102. package/dist/component/garmin/transform/bloodPressure.d.ts.map +1 -0
  103. package/dist/{garmin → component/garmin/transform}/bloodPressure.js +7 -8
  104. package/dist/component/garmin/transform/bloodPressure.js.map +1 -0
  105. package/dist/component/garmin/transform/bodyCompositions.d.ts +12 -0
  106. package/dist/component/garmin/transform/bodyCompositions.d.ts.map +1 -0
  107. package/dist/component/garmin/transform/bodyCompositions.js +42 -0
  108. package/dist/component/garmin/transform/bodyCompositions.js.map +1 -0
  109. package/dist/component/garmin/transform/dailies.d.ts +12 -0
  110. package/dist/component/garmin/transform/dailies.d.ts.map +1 -0
  111. package/dist/{garmin/daily.js → component/garmin/transform/dailies.js} +38 -49
  112. package/dist/component/garmin/transform/dailies.js.map +1 -0
  113. package/dist/component/garmin/transform/epochs.d.ts +13 -0
  114. package/dist/component/garmin/transform/epochs.d.ts.map +1 -0
  115. package/dist/component/garmin/transform/epochs.js +76 -0
  116. package/dist/component/garmin/transform/epochs.js.map +1 -0
  117. package/dist/component/garmin/transform/healthSnapshot.d.ts +12 -0
  118. package/dist/component/garmin/transform/healthSnapshot.d.ts.map +1 -0
  119. package/dist/component/garmin/transform/healthSnapshot.js +111 -0
  120. package/dist/component/garmin/transform/healthSnapshot.js.map +1 -0
  121. package/dist/component/garmin/transform/hrvSummary.d.ts +12 -0
  122. package/dist/component/garmin/transform/hrvSummary.d.ts.map +1 -0
  123. package/dist/{garmin/hrv.js → component/garmin/transform/hrvSummary.js} +16 -16
  124. package/dist/component/garmin/transform/hrvSummary.js.map +1 -0
  125. package/dist/component/garmin/transform/manuallyUpdatedActivities.d.ts +11 -0
  126. package/dist/component/garmin/transform/manuallyUpdatedActivities.d.ts.map +1 -0
  127. package/dist/component/garmin/transform/manuallyUpdatedActivities.js +20 -0
  128. package/dist/component/garmin/transform/manuallyUpdatedActivities.js.map +1 -0
  129. package/dist/{garmin/maps/activity-type.d.ts → component/garmin/transform/maps/activityType.d.ts} +1 -1
  130. package/dist/component/garmin/transform/maps/activityType.d.ts.map +1 -0
  131. package/dist/{garmin/maps/activity-type.js → component/garmin/transform/maps/activityType.js} +1 -1
  132. package/dist/component/garmin/transform/maps/activityType.js.map +1 -0
  133. package/dist/{garmin/maps/sleep-level.d.ts → component/garmin/transform/maps/sleepLevel.d.ts} +1 -1
  134. package/dist/component/garmin/transform/maps/sleepLevel.d.ts.map +1 -0
  135. package/dist/{garmin/maps/sleep-level.js → component/garmin/transform/maps/sleepLevel.js} +1 -1
  136. package/dist/component/garmin/transform/maps/sleepLevel.js.map +1 -0
  137. package/dist/component/garmin/transform/menstrualCycleTracking.d.ts +10 -0
  138. package/dist/component/garmin/transform/menstrualCycleTracking.d.ts.map +1 -0
  139. package/dist/{garmin/menstruation.js → component/garmin/transform/menstrualCycleTracking.js} +17 -12
  140. package/dist/component/garmin/transform/menstrualCycleTracking.js.map +1 -0
  141. package/dist/component/garmin/transform/moveIQ.d.ts +14 -0
  142. package/dist/component/garmin/transform/moveIQ.d.ts.map +1 -0
  143. package/dist/component/garmin/transform/moveIQ.js +41 -0
  144. package/dist/component/garmin/transform/moveIQ.js.map +1 -0
  145. package/dist/{garmin → component/garmin/transform}/plannedWorkout.d.ts +3 -4
  146. package/dist/component/garmin/transform/plannedWorkout.d.ts.map +1 -0
  147. package/dist/{garmin → component/garmin/transform}/plannedWorkout.js +61 -70
  148. package/dist/component/garmin/transform/plannedWorkout.js.map +1 -0
  149. package/dist/component/garmin/transform/pulseOx.d.ts +12 -0
  150. package/dist/component/garmin/transform/pulseOx.d.ts.map +1 -0
  151. package/dist/component/garmin/transform/pulseOx.js +46 -0
  152. package/dist/component/garmin/transform/pulseOx.js.map +1 -0
  153. package/dist/component/garmin/transform/respiration.d.ts +12 -0
  154. package/dist/component/garmin/transform/respiration.d.ts.map +1 -0
  155. package/dist/component/garmin/transform/respiration.js +54 -0
  156. package/dist/component/garmin/transform/respiration.js.map +1 -0
  157. package/dist/component/garmin/transform/skinTemperature.d.ts +12 -0
  158. package/dist/component/garmin/transform/skinTemperature.d.ts.map +1 -0
  159. package/dist/{garmin/skinTemp.js → component/garmin/transform/skinTemperature.js} +13 -10
  160. package/dist/component/garmin/transform/skinTemperature.js.map +1 -0
  161. package/dist/{garmin/sleep.d.ts → component/garmin/transform/sleeps.d.ts} +13 -20
  162. package/dist/component/garmin/transform/sleeps.d.ts.map +1 -0
  163. package/dist/{garmin/sleep.js → component/garmin/transform/sleeps.js} +39 -50
  164. package/dist/component/garmin/transform/sleeps.js.map +1 -0
  165. package/dist/component/garmin/transform/stress.d.ts +12 -0
  166. package/dist/component/garmin/transform/stress.d.ts.map +1 -0
  167. package/dist/component/garmin/transform/stress.js +56 -0
  168. package/dist/component/garmin/transform/stress.js.map +1 -0
  169. package/dist/component/garmin/transform/userMetrics.d.ts +12 -0
  170. package/dist/component/garmin/transform/userMetrics.d.ts.map +1 -0
  171. package/dist/{garmin → component/garmin/transform}/userMetrics.js +19 -12
  172. package/dist/component/garmin/transform/userMetrics.js.map +1 -0
  173. package/dist/component/garmin/types/trainingApiWorkouts/client/client.gen.d.ts +3 -0
  174. package/dist/component/garmin/types/trainingApiWorkouts/client/client.gen.d.ts.map +1 -0
  175. package/dist/component/garmin/types/trainingApiWorkouts/client/client.gen.js +236 -0
  176. package/dist/component/garmin/types/trainingApiWorkouts/client/client.gen.js.map +1 -0
  177. package/dist/component/garmin/types/trainingApiWorkouts/client/index.d.ts +9 -0
  178. package/dist/component/garmin/types/trainingApiWorkouts/client/index.d.ts.map +1 -0
  179. package/dist/component/garmin/types/trainingApiWorkouts/client/index.js +7 -0
  180. package/dist/component/garmin/types/trainingApiWorkouts/client/index.js.map +1 -0
  181. package/dist/component/garmin/types/trainingApiWorkouts/client/types.gen.d.ts +118 -0
  182. package/dist/component/garmin/types/trainingApiWorkouts/client/types.gen.d.ts.map +1 -0
  183. package/dist/component/garmin/types/trainingApiWorkouts/client/types.gen.js +3 -0
  184. package/dist/component/garmin/types/trainingApiWorkouts/client/types.gen.js.map +1 -0
  185. package/dist/component/garmin/types/trainingApiWorkouts/client/utils.gen.d.ts +34 -0
  186. package/dist/component/garmin/types/trainingApiWorkouts/client/utils.gen.d.ts.map +1 -0
  187. package/dist/component/garmin/types/trainingApiWorkouts/client/utils.gen.js +229 -0
  188. package/dist/component/garmin/types/trainingApiWorkouts/client/utils.gen.js.map +1 -0
  189. package/dist/component/garmin/types/trainingApiWorkouts/client.gen.d.ts +13 -0
  190. package/dist/component/garmin/types/trainingApiWorkouts/client.gen.d.ts.map +1 -0
  191. package/dist/component/garmin/types/trainingApiWorkouts/client.gen.js +4 -0
  192. package/dist/component/garmin/types/trainingApiWorkouts/client.gen.js.map +1 -0
  193. package/dist/component/garmin/types/trainingApiWorkouts/core/auth.gen.d.ts +19 -0
  194. package/dist/component/garmin/types/trainingApiWorkouts/core/auth.gen.d.ts.map +1 -0
  195. package/dist/component/garmin/types/trainingApiWorkouts/core/auth.gen.js +15 -0
  196. package/dist/component/garmin/types/trainingApiWorkouts/core/auth.gen.js.map +1 -0
  197. package/dist/component/garmin/types/trainingApiWorkouts/core/bodySerializer.gen.d.ts +26 -0
  198. package/dist/component/garmin/types/trainingApiWorkouts/core/bodySerializer.gen.d.ts.map +1 -0
  199. package/dist/component/garmin/types/trainingApiWorkouts/core/bodySerializer.gen.js +58 -0
  200. package/dist/component/garmin/types/trainingApiWorkouts/core/bodySerializer.gen.js.map +1 -0
  201. package/dist/component/garmin/types/trainingApiWorkouts/core/params.gen.d.ts +44 -0
  202. package/dist/component/garmin/types/trainingApiWorkouts/core/params.gen.d.ts.map +1 -0
  203. package/dist/component/garmin/types/trainingApiWorkouts/core/params.gen.js +101 -0
  204. package/dist/component/garmin/types/trainingApiWorkouts/core/params.gen.js.map +1 -0
  205. package/dist/component/garmin/types/trainingApiWorkouts/core/pathSerializer.gen.d.ts +34 -0
  206. package/dist/component/garmin/types/trainingApiWorkouts/core/pathSerializer.gen.d.ts.map +1 -0
  207. package/dist/component/garmin/types/trainingApiWorkouts/core/pathSerializer.gen.js +107 -0
  208. package/dist/component/garmin/types/trainingApiWorkouts/core/pathSerializer.gen.js.map +1 -0
  209. package/dist/component/garmin/types/trainingApiWorkouts/core/queryKeySerializer.gen.d.ts +19 -0
  210. package/dist/component/garmin/types/trainingApiWorkouts/core/queryKeySerializer.gen.d.ts.map +1 -0
  211. package/dist/component/garmin/types/trainingApiWorkouts/core/queryKeySerializer.gen.js +93 -0
  212. package/dist/component/garmin/types/trainingApiWorkouts/core/queryKeySerializer.gen.js.map +1 -0
  213. package/dist/component/garmin/types/trainingApiWorkouts/core/serverSentEvents.gen.d.ts +72 -0
  214. package/dist/component/garmin/types/trainingApiWorkouts/core/serverSentEvents.gen.d.ts.map +1 -0
  215. package/dist/component/garmin/types/trainingApiWorkouts/core/serverSentEvents.gen.js +134 -0
  216. package/dist/component/garmin/types/trainingApiWorkouts/core/serverSentEvents.gen.js.map +1 -0
  217. package/dist/component/garmin/types/trainingApiWorkouts/core/types.gen.d.ts +79 -0
  218. package/dist/component/garmin/types/trainingApiWorkouts/core/types.gen.d.ts.map +1 -0
  219. package/dist/component/garmin/types/trainingApiWorkouts/core/types.gen.js +3 -0
  220. package/dist/component/garmin/types/trainingApiWorkouts/core/types.gen.js.map +1 -0
  221. package/dist/component/garmin/types/trainingApiWorkouts/core/utils.gen.d.ts +20 -0
  222. package/dist/component/garmin/types/trainingApiWorkouts/core/utils.gen.d.ts.map +1 -0
  223. package/dist/component/garmin/types/trainingApiWorkouts/core/utils.gen.js +88 -0
  224. package/dist/component/garmin/types/trainingApiWorkouts/core/utils.gen.js.map +1 -0
  225. package/dist/component/garmin/types/trainingApiWorkouts/index.d.ts +3 -0
  226. package/dist/component/garmin/types/trainingApiWorkouts/index.d.ts.map +1 -0
  227. package/dist/component/garmin/types/trainingApiWorkouts/index.js +3 -0
  228. package/dist/component/garmin/types/trainingApiWorkouts/index.js.map +1 -0
  229. package/dist/component/garmin/types/trainingApiWorkouts/sdk.gen.d.ts +68 -0
  230. package/dist/component/garmin/types/trainingApiWorkouts/sdk.gen.d.ts.map +1 -0
  231. package/dist/component/garmin/types/trainingApiWorkouts/sdk.gen.js +97 -0
  232. package/dist/component/garmin/types/trainingApiWorkouts/sdk.gen.js.map +1 -0
  233. package/dist/component/garmin/types/trainingApiWorkouts/types.gen.d.ts +330 -0
  234. package/dist/component/garmin/types/trainingApiWorkouts/types.gen.d.ts.map +1 -0
  235. package/dist/component/garmin/types/trainingApiWorkouts/types.gen.js +3 -0
  236. package/dist/component/garmin/types/trainingApiWorkouts/types.gen.js.map +1 -0
  237. package/dist/component/garmin/types/trainingApiWorkouts/zod.gen.d.ts +2463 -0
  238. package/dist/component/garmin/types/trainingApiWorkouts/zod.gen.d.ts.map +1 -0
  239. package/dist/component/garmin/types/trainingApiWorkouts/zod.gen.js +388 -0
  240. package/dist/component/garmin/types/trainingApiWorkouts/zod.gen.js.map +1 -0
  241. package/dist/component/garmin/types/wellnessApi/client/client.gen.d.ts +3 -0
  242. package/dist/component/garmin/types/wellnessApi/client/client.gen.d.ts.map +1 -0
  243. package/dist/component/garmin/types/wellnessApi/client/client.gen.js +236 -0
  244. package/dist/component/garmin/types/wellnessApi/client/client.gen.js.map +1 -0
  245. package/dist/component/garmin/types/wellnessApi/client/index.d.ts +9 -0
  246. package/dist/component/garmin/types/wellnessApi/client/index.d.ts.map +1 -0
  247. package/dist/component/garmin/types/wellnessApi/client/index.js +7 -0
  248. package/dist/component/garmin/types/wellnessApi/client/index.js.map +1 -0
  249. package/dist/component/garmin/types/wellnessApi/client/types.gen.d.ts +118 -0
  250. package/dist/component/garmin/types/wellnessApi/client/types.gen.d.ts.map +1 -0
  251. package/dist/component/garmin/types/wellnessApi/client/types.gen.js +3 -0
  252. package/dist/component/garmin/types/wellnessApi/client/types.gen.js.map +1 -0
  253. package/dist/component/garmin/types/wellnessApi/client/utils.gen.d.ts +34 -0
  254. package/dist/component/garmin/types/wellnessApi/client/utils.gen.d.ts.map +1 -0
  255. package/dist/component/garmin/types/wellnessApi/client/utils.gen.js +229 -0
  256. package/dist/component/garmin/types/wellnessApi/client/utils.gen.js.map +1 -0
  257. package/dist/component/garmin/types/wellnessApi/client.gen.d.ts +13 -0
  258. package/dist/component/garmin/types/wellnessApi/client.gen.d.ts.map +1 -0
  259. package/dist/component/garmin/types/wellnessApi/client.gen.js +4 -0
  260. package/dist/component/garmin/types/wellnessApi/client.gen.js.map +1 -0
  261. package/dist/component/garmin/types/wellnessApi/core/auth.gen.d.ts +19 -0
  262. package/dist/component/garmin/types/wellnessApi/core/auth.gen.d.ts.map +1 -0
  263. package/dist/component/garmin/types/wellnessApi/core/auth.gen.js +15 -0
  264. package/dist/component/garmin/types/wellnessApi/core/auth.gen.js.map +1 -0
  265. package/dist/component/garmin/types/wellnessApi/core/bodySerializer.gen.d.ts +26 -0
  266. package/dist/component/garmin/types/wellnessApi/core/bodySerializer.gen.d.ts.map +1 -0
  267. package/dist/component/garmin/types/wellnessApi/core/bodySerializer.gen.js +58 -0
  268. package/dist/component/garmin/types/wellnessApi/core/bodySerializer.gen.js.map +1 -0
  269. package/dist/component/garmin/types/wellnessApi/core/params.gen.d.ts +44 -0
  270. package/dist/component/garmin/types/wellnessApi/core/params.gen.d.ts.map +1 -0
  271. package/dist/component/garmin/types/wellnessApi/core/params.gen.js +101 -0
  272. package/dist/component/garmin/types/wellnessApi/core/params.gen.js.map +1 -0
  273. package/dist/component/garmin/types/wellnessApi/core/pathSerializer.gen.d.ts +34 -0
  274. package/dist/component/garmin/types/wellnessApi/core/pathSerializer.gen.d.ts.map +1 -0
  275. package/dist/component/garmin/types/wellnessApi/core/pathSerializer.gen.js +107 -0
  276. package/dist/component/garmin/types/wellnessApi/core/pathSerializer.gen.js.map +1 -0
  277. package/dist/component/garmin/types/wellnessApi/core/queryKeySerializer.gen.d.ts +19 -0
  278. package/dist/component/garmin/types/wellnessApi/core/queryKeySerializer.gen.d.ts.map +1 -0
  279. package/dist/component/garmin/types/wellnessApi/core/queryKeySerializer.gen.js +93 -0
  280. package/dist/component/garmin/types/wellnessApi/core/queryKeySerializer.gen.js.map +1 -0
  281. package/dist/component/garmin/types/wellnessApi/core/serverSentEvents.gen.d.ts +72 -0
  282. package/dist/component/garmin/types/wellnessApi/core/serverSentEvents.gen.d.ts.map +1 -0
  283. package/dist/component/garmin/types/wellnessApi/core/serverSentEvents.gen.js +134 -0
  284. package/dist/component/garmin/types/wellnessApi/core/serverSentEvents.gen.js.map +1 -0
  285. package/dist/component/garmin/types/wellnessApi/core/types.gen.d.ts +79 -0
  286. package/dist/component/garmin/types/wellnessApi/core/types.gen.d.ts.map +1 -0
  287. package/dist/component/garmin/types/wellnessApi/core/types.gen.js +3 -0
  288. package/dist/component/garmin/types/wellnessApi/core/types.gen.js.map +1 -0
  289. package/dist/component/garmin/types/wellnessApi/core/utils.gen.d.ts +20 -0
  290. package/dist/component/garmin/types/wellnessApi/core/utils.gen.d.ts.map +1 -0
  291. package/dist/component/garmin/types/wellnessApi/core/utils.gen.js +88 -0
  292. package/dist/component/garmin/types/wellnessApi/core/utils.gen.js.map +1 -0
  293. package/dist/component/garmin/types/wellnessApi/index.d.ts +3 -0
  294. package/dist/component/garmin/types/wellnessApi/index.d.ts.map +1 -0
  295. package/dist/component/garmin/types/wellnessApi/index.js +3 -0
  296. package/dist/component/garmin/types/wellnessApi/index.js.map +1 -0
  297. package/dist/component/garmin/types/wellnessApi/sdk.gen.d.ts +166 -0
  298. package/dist/component/garmin/types/wellnessApi/sdk.gen.d.ts.map +1 -0
  299. package/dist/component/garmin/types/wellnessApi/sdk.gen.js +153 -0
  300. package/dist/component/garmin/types/wellnessApi/sdk.gen.js.map +1 -0
  301. package/dist/component/garmin/types/wellnessApi/types.gen.d.ts +2733 -0
  302. package/dist/component/garmin/types/wellnessApi/types.gen.d.ts.map +1 -0
  303. package/dist/component/garmin/types/wellnessApi/types.gen.js +3 -0
  304. package/dist/component/garmin/types/wellnessApi/types.gen.js.map +1 -0
  305. package/dist/component/garmin/types/wellnessApi/zod.gen.d.ts +1319 -0
  306. package/dist/component/garmin/types/wellnessApi/zod.gen.d.ts.map +1 -0
  307. package/dist/component/garmin/types/wellnessApi/zod.gen.js +784 -0
  308. package/dist/component/garmin/types/wellnessApi/zod.gen.js.map +1 -0
  309. package/dist/component/garmin/utils.d.ts +16 -0
  310. package/dist/component/garmin/utils.d.ts.map +1 -0
  311. package/dist/component/garmin/utils.js +17 -0
  312. package/dist/component/garmin/utils.js.map +1 -0
  313. package/dist/component/garmin/webhooks.d.ts +128 -0
  314. package/dist/component/garmin/webhooks.d.ts.map +1 -0
  315. package/dist/component/garmin/webhooks.js +531 -0
  316. package/dist/component/garmin/webhooks.js.map +1 -0
  317. package/dist/component/private.d.ts +4 -4
  318. package/dist/component/public.d.ts +333 -333
  319. package/dist/component/schema.d.ts +133 -133
  320. package/dist/component/strava/private.d.ts +30 -0
  321. package/dist/component/strava/private.d.ts.map +1 -0
  322. package/dist/component/strava/private.js +71 -0
  323. package/dist/component/strava/private.js.map +1 -0
  324. package/dist/component/{strava.d.ts → strava/public.d.ts} +3 -31
  325. package/dist/component/strava/public.d.ts.map +1 -0
  326. package/dist/component/{strava.js → strava/public.js} +22 -101
  327. package/dist/component/strava/public.js.map +1 -0
  328. package/dist/component/validators/activity.d.ts +6 -0
  329. package/dist/component/validators/activity.d.ts.map +1 -1
  330. package/dist/component/validators/activity.js.map +1 -1
  331. package/dist/component/validators/body.d.ts +20 -14
  332. package/dist/component/validators/body.d.ts.map +1 -1
  333. package/dist/component/validators/body.js.map +1 -1
  334. package/dist/component/validators/daily.d.ts +6 -0
  335. package/dist/component/validators/daily.d.ts.map +1 -1
  336. package/dist/component/validators/daily.js.map +1 -1
  337. package/dist/component/validators/enums.d.ts +1 -1
  338. package/dist/component/validators/menstruation.d.ts +5 -0
  339. package/dist/component/validators/menstruation.d.ts.map +1 -1
  340. package/dist/component/validators/menstruation.js.map +1 -1
  341. package/dist/component/validators/plannedWorkout.d.ts +6 -0
  342. package/dist/component/validators/plannedWorkout.d.ts.map +1 -1
  343. package/dist/component/validators/plannedWorkout.js.map +1 -1
  344. package/dist/validators.d.ts +31 -28
  345. package/dist/validators.d.ts.map +1 -1
  346. package/dist/validators.js +2 -2
  347. package/dist/validators.js.map +1 -1
  348. package/package.json +4 -7
  349. package/src/client/index.ts +41 -172
  350. package/src/component/_generated/api.ts +98 -4
  351. package/src/component/_generated/component.ts +252 -284
  352. package/src/{garmin → component/garmin}/auth.ts +8 -1
  353. package/src/component/garmin/client.ts +39 -0
  354. package/src/component/garmin/private.ts +1798 -0
  355. package/src/component/garmin/public.ts +938 -0
  356. package/src/component/garmin/schemas/activity.ts +40 -0
  357. package/src/component/garmin/schemas/activityDetails.ts +45 -0
  358. package/src/component/garmin/schemas/bloodPressure.ts +38 -0
  359. package/src/component/garmin/schemas/bodyCompositions.ts +38 -0
  360. package/src/component/garmin/schemas/dailies.ts +38 -0
  361. package/src/component/garmin/schemas/epochs.ts +38 -0
  362. package/src/component/garmin/schemas/healthSnapshot.ts +38 -0
  363. package/src/component/garmin/schemas/hrvSummary.ts +38 -0
  364. package/src/component/garmin/schemas/manuallyUpdatedActivities.ts +49 -0
  365. package/src/component/garmin/schemas/menstrualCycleTracking.ts +39 -0
  366. package/src/component/garmin/schemas/moveIQ.ts +38 -0
  367. package/src/component/garmin/schemas/pulseOx.ts +39 -0
  368. package/src/component/garmin/schemas/respiration.ts +39 -0
  369. package/src/component/garmin/schemas/skinTemperature.ts +39 -0
  370. package/src/component/garmin/schemas/sleeps.ts +38 -0
  371. package/src/component/garmin/schemas/stress.ts +43 -0
  372. package/src/component/garmin/schemas/userMetrics.ts +39 -0
  373. package/src/component/garmin/transform/activity.ts +143 -0
  374. package/src/component/garmin/transform/activityDetails.ts +236 -0
  375. package/src/{garmin → component/garmin/transform}/bloodPressure.ts +39 -41
  376. package/src/component/garmin/transform/bodyCompositions.ts +51 -0
  377. package/src/component/garmin/transform/dailies.ts +179 -0
  378. package/src/component/garmin/transform/epochs.ts +94 -0
  379. package/src/component/garmin/transform/healthSnapshot.ts +152 -0
  380. package/src/component/garmin/transform/hrvSummary.ts +56 -0
  381. package/src/component/garmin/transform/manuallyUpdatedActivities.ts +27 -0
  382. package/src/{garmin/maps/activity-type.ts → component/garmin/transform/maps/activityType.ts} +116 -116
  383. package/src/{garmin/maps/sleep-level.ts → component/garmin/transform/maps/sleepLevel.ts} +22 -22
  384. package/src/component/garmin/transform/menstrualCycleTracking.ts +48 -0
  385. package/src/component/garmin/transform/moveIQ.ts +48 -0
  386. package/src/{garmin → component/garmin/transform}/plannedWorkout.ts +328 -333
  387. package/src/component/garmin/transform/pulseOx.ts +64 -0
  388. package/src/component/garmin/transform/respiration.ts +73 -0
  389. package/src/component/garmin/transform/skinTemperature.ts +44 -0
  390. package/src/component/garmin/transform/sleeps.ts +159 -0
  391. package/src/component/garmin/transform/stress.ts +78 -0
  392. package/src/component/garmin/transform/userMetrics.ts +56 -0
  393. package/src/component/garmin/types/specs/training-api-workouts.json +699 -0
  394. package/src/component/garmin/types/trainingApiWorkouts/client/client.gen.ts +290 -0
  395. package/src/component/garmin/types/trainingApiWorkouts/client/index.ts +25 -0
  396. package/src/component/garmin/types/trainingApiWorkouts/client/types.gen.ts +214 -0
  397. package/src/component/garmin/types/trainingApiWorkouts/client/utils.gen.ts +316 -0
  398. package/src/component/garmin/types/trainingApiWorkouts/client.gen.ts +16 -0
  399. package/src/component/garmin/types/trainingApiWorkouts/core/auth.gen.ts +41 -0
  400. package/src/component/garmin/types/trainingApiWorkouts/core/bodySerializer.gen.ts +82 -0
  401. package/src/component/garmin/types/trainingApiWorkouts/core/params.gen.ts +169 -0
  402. package/src/component/garmin/types/trainingApiWorkouts/core/pathSerializer.gen.ts +171 -0
  403. package/src/component/garmin/types/trainingApiWorkouts/core/queryKeySerializer.gen.ts +117 -0
  404. package/src/component/garmin/types/trainingApiWorkouts/core/serverSentEvents.gen.ts +243 -0
  405. package/src/component/garmin/types/trainingApiWorkouts/core/types.gen.ts +104 -0
  406. package/src/component/garmin/types/trainingApiWorkouts/core/utils.gen.ts +140 -0
  407. package/src/component/garmin/types/trainingApiWorkouts/index.ts +4 -0
  408. package/src/component/garmin/types/trainingApiWorkouts/sdk.gen.ts +126 -0
  409. package/src/component/garmin/types/trainingApiWorkouts/types.gen.ts +387 -0
  410. package/src/component/garmin/types/trainingApiWorkouts/zod.gen.ts +423 -0
  411. package/src/component/garmin/types/wellnessApi/client/client.gen.ts +290 -0
  412. package/src/component/garmin/types/wellnessApi/client/index.ts +25 -0
  413. package/src/component/garmin/types/wellnessApi/client/types.gen.ts +214 -0
  414. package/src/component/garmin/types/wellnessApi/client/utils.gen.ts +316 -0
  415. package/src/component/garmin/types/wellnessApi/client.gen.ts +16 -0
  416. package/src/component/garmin/types/wellnessApi/core/auth.gen.ts +41 -0
  417. package/src/component/garmin/types/wellnessApi/core/bodySerializer.gen.ts +82 -0
  418. package/src/component/garmin/types/wellnessApi/core/params.gen.ts +169 -0
  419. package/src/component/garmin/types/wellnessApi/core/pathSerializer.gen.ts +171 -0
  420. package/src/component/garmin/types/wellnessApi/core/queryKeySerializer.gen.ts +117 -0
  421. package/src/component/garmin/types/wellnessApi/core/serverSentEvents.gen.ts +243 -0
  422. package/src/component/garmin/types/wellnessApi/core/types.gen.ts +104 -0
  423. package/src/component/garmin/types/wellnessApi/core/utils.gen.ts +140 -0
  424. package/src/component/garmin/types/wellnessApi/index.ts +4 -0
  425. package/src/component/garmin/types/wellnessApi/sdk.gen.ts +207 -0
  426. package/src/component/garmin/types/wellnessApi/types.gen.ts +2942 -0
  427. package/src/component/garmin/types/wellnessApi/zod.gen.ts +878 -0
  428. package/src/component/garmin/utils.ts +25 -0
  429. package/src/component/garmin/webhooks.ts +852 -0
  430. package/src/component/strava/private.ts +89 -0
  431. package/src/component/{strava.ts → strava/public.ts} +341 -404
  432. package/src/component/validators/activity.ts +5 -0
  433. package/src/component/validators/body.ts +5 -0
  434. package/src/component/validators/daily.ts +5 -0
  435. package/src/component/validators/menstruation.ts +5 -1
  436. package/src/component/validators/plannedWorkout.ts +5 -0
  437. package/src/validators.ts +12 -2
  438. package/dist/component/garmin.d.ts +0 -366
  439. package/dist/component/garmin.d.ts.map +0 -1
  440. package/dist/component/garmin.js +0 -1481
  441. package/dist/component/garmin.js.map +0 -1
  442. package/dist/component/strava.d.ts.map +0 -1
  443. package/dist/component/strava.js.map +0 -1
  444. package/dist/garmin/activity.d.ts +0 -92
  445. package/dist/garmin/activity.d.ts.map +0 -1
  446. package/dist/garmin/activity.js +0 -201
  447. package/dist/garmin/activity.js.map +0 -1
  448. package/dist/garmin/auth.d.ts.map +0 -1
  449. package/dist/garmin/auth.js.map +0 -1
  450. package/dist/garmin/bloodPressure.d.ts +0 -28
  451. package/dist/garmin/bloodPressure.d.ts.map +0 -1
  452. package/dist/garmin/bloodPressure.js.map +0 -1
  453. package/dist/garmin/body.d.ts +0 -26
  454. package/dist/garmin/body.d.ts.map +0 -1
  455. package/dist/garmin/body.js +0 -44
  456. package/dist/garmin/body.js.map +0 -1
  457. package/dist/garmin/client.d.ts +0 -246
  458. package/dist/garmin/client.d.ts.map +0 -1
  459. package/dist/garmin/client.js +0 -566
  460. package/dist/garmin/client.js.map +0 -1
  461. package/dist/garmin/daily.d.ts +0 -74
  462. package/dist/garmin/daily.d.ts.map +0 -1
  463. package/dist/garmin/daily.js.map +0 -1
  464. package/dist/garmin/hrv.d.ts +0 -30
  465. package/dist/garmin/hrv.d.ts.map +0 -1
  466. package/dist/garmin/hrv.js.map +0 -1
  467. package/dist/garmin/index.d.ts +0 -34
  468. package/dist/garmin/index.d.ts.map +0 -1
  469. package/dist/garmin/index.js +0 -28
  470. package/dist/garmin/index.js.map +0 -1
  471. package/dist/garmin/maps/activity-type.d.ts.map +0 -1
  472. package/dist/garmin/maps/activity-type.js.map +0 -1
  473. package/dist/garmin/maps/sleep-level.d.ts.map +0 -1
  474. package/dist/garmin/maps/sleep-level.js.map +0 -1
  475. package/dist/garmin/menstruation.d.ts +0 -25
  476. package/dist/garmin/menstruation.d.ts.map +0 -1
  477. package/dist/garmin/menstruation.js.map +0 -1
  478. package/dist/garmin/plannedWorkout.d.ts.map +0 -1
  479. package/dist/garmin/plannedWorkout.js.map +0 -1
  480. package/dist/garmin/pulseOx.d.ts +0 -24
  481. package/dist/garmin/pulseOx.d.ts.map +0 -1
  482. package/dist/garmin/pulseOx.js +0 -33
  483. package/dist/garmin/pulseOx.js.map +0 -1
  484. package/dist/garmin/respiration.d.ts +0 -29
  485. package/dist/garmin/respiration.d.ts.map +0 -1
  486. package/dist/garmin/respiration.js +0 -42
  487. package/dist/garmin/respiration.js.map +0 -1
  488. package/dist/garmin/skinTemp.d.ts +0 -27
  489. package/dist/garmin/skinTemp.d.ts.map +0 -1
  490. package/dist/garmin/skinTemp.js.map +0 -1
  491. package/dist/garmin/sleep.d.ts.map +0 -1
  492. package/dist/garmin/sleep.js.map +0 -1
  493. package/dist/garmin/stressDetails.d.ts +0 -30
  494. package/dist/garmin/stressDetails.d.ts.map +0 -1
  495. package/dist/garmin/stressDetails.js +0 -49
  496. package/dist/garmin/stressDetails.js.map +0 -1
  497. package/dist/garmin/sync.d.ts +0 -53
  498. package/dist/garmin/sync.d.ts.map +0 -1
  499. package/dist/garmin/sync.js +0 -457
  500. package/dist/garmin/sync.js.map +0 -1
  501. package/dist/garmin/types.d.ts +0 -175
  502. package/dist/garmin/types.d.ts.map +0 -1
  503. package/dist/garmin/types.js +0 -10
  504. package/dist/garmin/types.js.map +0 -1
  505. package/dist/garmin/userMetrics.d.ts +0 -23
  506. package/dist/garmin/userMetrics.d.ts.map +0 -1
  507. package/dist/garmin/userMetrics.js.map +0 -1
  508. package/src/component/garmin.ts +0 -1722
  509. package/src/garmin/activity.test.ts +0 -170
  510. package/src/garmin/activity.ts +0 -265
  511. package/src/garmin/auth.test.ts +0 -103
  512. package/src/garmin/body.ts +0 -59
  513. package/src/garmin/client.ts +0 -886
  514. package/src/garmin/daily.ts +0 -215
  515. package/src/garmin/hrv.ts +0 -57
  516. package/src/garmin/index.ts +0 -145
  517. package/src/garmin/maps/activity-type.test.ts +0 -78
  518. package/src/garmin/menstruation.ts +0 -44
  519. package/src/garmin/pulseOx.ts +0 -45
  520. package/src/garmin/respiration.ts +0 -55
  521. package/src/garmin/skinTemp.ts +0 -42
  522. package/src/garmin/sleep.test.ts +0 -109
  523. package/src/garmin/sleep.ts +0 -176
  524. package/src/garmin/stressDetails.ts +0 -71
  525. package/src/garmin/sync.ts +0 -566
  526. package/src/garmin/types.ts +0 -268
  527. package/src/garmin/userMetrics.ts +0 -50
  528. package/src/garmin/wellness-api.d.ts +0 -5637
  529. /package/dist/{garmin → component/garmin}/auth.js +0 -0
  530. /package/src/{garmin/spec → component/garmin/types/specs}/wellness-api.json +0 -0
@@ -0,0 +1,1461 @@
1
+ // ─── Garmin Internal Mutations ───────────────────────────────────────────────
2
+ // Token CRUD and pending OAuth state management.
3
+ // Called only from garmin/public.ts and garmin/webhooks.ts.
4
+ import { v } from "convex/values";
5
+ import { internalAction, internalMutation, internalQuery, } from "../_generated/server";
6
+ import { internal } from "../_generated/api";
7
+ import { garminActivityPingPayloadSchema, garminActivityPushPayloadSchema, } from "./schemas/activity.js";
8
+ import { garminActivityDetailsPingPayloadSchema, garminActivityDetailsPushPayloadSchema, } from "./schemas/activityDetails.js";
9
+ import { garminManuallyUpdatedActivitiesPingPayloadSchema, garminManuallyUpdatedActivitiesPushPayloadSchema, } from "./schemas/manuallyUpdatedActivities.js";
10
+ import { garminMoveIQPingPayloadSchema, garminMoveIQPushPayloadSchema, } from "./schemas/moveIQ.js";
11
+ import { garminBloodPressurePingPayloadSchema, garminBloodPressurePushPayloadSchema, } from "./schemas/bloodPressure.js";
12
+ import { garminBodyCompositionsPingPayloadSchema, garminBodyCompositionsPushPayloadSchema, } from "./schemas/bodyCompositions.js";
13
+ import { garminDailiesPingPayloadSchema, garminDailiesPushPayloadSchema, } from "./schemas/dailies.js";
14
+ import { garminHealthSnapshotPingPayloadSchema, garminHealthSnapshotPushPayloadSchema, } from "./schemas/healthSnapshot.js";
15
+ import { garminHRVSummaryPingPayloadSchema, garminHRVSummaryPushPayloadSchema, } from "./schemas/hrvSummary.js";
16
+ import { garminEpochPingPayloadSchema, garminEpochPushPayloadSchema, } from "./schemas/epochs.js";
17
+ import { garminPulseOxPingPayloadSchema, garminPulseOxPushPayloadSchema, } from "./schemas/pulseOx.js";
18
+ import { garminRespirationPingPayloadSchema, garminRespirationPushPayloadSchema, } from "./schemas/respiration.js";
19
+ import { garminSkinTemperaturePingPayloadSchema, garminSkinTemperaturePushPayloadSchema, } from "./schemas/skinTemperature.js";
20
+ import { garminStressPingPayloadSchema, garminStressPushPayloadSchema, } from "./schemas/stress.js";
21
+ import { garminSleepsPingPayloadSchema, garminSleepsPushPayloadSchema, } from "./schemas/sleeps.js";
22
+ import { transformActivity } from "./transform/activity.js";
23
+ import { transformActivityDetails } from "./transform/activityDetails.js";
24
+ import { transformManuallyUpdatedActivity } from "./transform/manuallyUpdatedActivities.js";
25
+ import { transformMoveIQ } from "./transform/moveIQ.js";
26
+ import { transformBloodPressure } from "./transform/bloodPressure.js";
27
+ import { transformBodyComposition } from "./transform/bodyCompositions.js";
28
+ import { transformDailies } from "./transform/dailies.js";
29
+ import { transformEpoch } from "./transform/epochs.js";
30
+ import { transformHealthSnapshot } from "./transform/healthSnapshot.js";
31
+ import { transformHRVSummary } from "./transform/hrvSummary.js";
32
+ import { transformPulseOx } from "./transform/pulseOx.js";
33
+ import { transformRespiration } from "./transform/respiration.js";
34
+ import { transformSkinTemperature } from "./transform/skinTemperature.js";
35
+ import { transformSleeps } from "./transform/sleeps.js";
36
+ import { transformStress } from "./transform/stress.js";
37
+ import { garminUserMetricsPingPayloadSchema, garminUserMetricsPushPayloadSchema, } from "./schemas/userMetrics.js";
38
+ import { transformUserMetrics } from "./transform/userMetrics.js";
39
+ import { garminMenstrualCycleTrackingPingPayloadSchema, garminMenstrualCycleTrackingPushPayloadSchema, } from "./schemas/menstrualCycleTracking.js";
40
+ import { transformMenstrualCycleTracking } from "./transform/menstrualCycleTracking.js";
41
+ // ─── Internal Pending OAuth CRUD ─────────────────────────────────────────────
42
+ // Temporary storage for in-progress Garmin OAuth 2.0 PKCE flows.
43
+ // Bridges getGarminAuthUrl and completeGarminOAuth.
44
+ export const storePendingOAuth = internalMutation({
45
+ args: {
46
+ provider: v.string(),
47
+ state: v.string(),
48
+ codeVerifier: v.string(),
49
+ userId: v.string(),
50
+ },
51
+ returns: v.null(),
52
+ handler: async (ctx, args) => {
53
+ await ctx.db.insert("pendingOAuth", {
54
+ ...args,
55
+ createdAt: Date.now(),
56
+ });
57
+ return null;
58
+ },
59
+ });
60
+ export const getPendingOAuth = internalQuery({
61
+ args: { state: v.string() },
62
+ returns: v.union(v.object({
63
+ _id: v.id("pendingOAuth"),
64
+ _creationTime: v.number(),
65
+ provider: v.string(),
66
+ state: v.string(),
67
+ codeVerifier: v.string(),
68
+ userId: v.string(),
69
+ createdAt: v.number(),
70
+ }), v.null()),
71
+ handler: async (ctx, args) => {
72
+ return await ctx.db
73
+ .query("pendingOAuth")
74
+ .withIndex("by_state", (q) => q.eq("state", args.state))
75
+ .first();
76
+ },
77
+ });
78
+ export const deletePendingOAuth = internalMutation({
79
+ args: { state: v.string() },
80
+ returns: v.null(),
81
+ handler: async (ctx, args) => {
82
+ const pending = await ctx.db
83
+ .query("pendingOAuth")
84
+ .withIndex("by_state", (q) => q.eq("state", args.state))
85
+ .first();
86
+ if (pending) {
87
+ await ctx.db.delete(pending._id);
88
+ }
89
+ return null;
90
+ },
91
+ });
92
+ // ─── Internal Token CRUD ─────────────────────────────────────────────────────
93
+ /**
94
+ * Store OAuth 2.0 tokens for a Garmin connection.
95
+ * Upserts by connectionId — one token record per connection.
96
+ */
97
+ export const storeTokens = internalMutation({
98
+ args: {
99
+ connectionId: v.id("connections"),
100
+ accessToken: v.string(),
101
+ refreshToken: v.string(),
102
+ expiresAt: v.number(),
103
+ },
104
+ returns: v.null(),
105
+ handler: async (ctx, args) => {
106
+ const existing = await ctx.db
107
+ .query("providerTokens")
108
+ .withIndex("by_connectionId", (q) => q.eq("connectionId", args.connectionId))
109
+ .first();
110
+ if (existing) {
111
+ await ctx.db.patch(existing._id, {
112
+ accessToken: args.accessToken,
113
+ refreshToken: args.refreshToken,
114
+ expiresAt: args.expiresAt,
115
+ });
116
+ return null;
117
+ }
118
+ await ctx.db.insert("providerTokens", {
119
+ connectionId: args.connectionId,
120
+ accessToken: args.accessToken,
121
+ refreshToken: args.refreshToken,
122
+ expiresAt: args.expiresAt,
123
+ });
124
+ return null;
125
+ },
126
+ });
127
+ /**
128
+ * Get stored tokens for a connection.
129
+ */
130
+ export const getTokens = internalQuery({
131
+ args: { connectionId: v.id("connections") },
132
+ returns: v.union(v.object({
133
+ _id: v.id("providerTokens"),
134
+ _creationTime: v.number(),
135
+ connectionId: v.id("connections"),
136
+ accessToken: v.string(),
137
+ refreshToken: v.optional(v.string()),
138
+ expiresAt: v.optional(v.number()),
139
+ }), v.null()),
140
+ handler: async (ctx, args) => {
141
+ return await ctx.db
142
+ .query("providerTokens")
143
+ .withIndex("by_connectionId", (q) => q.eq("connectionId", args.connectionId))
144
+ .first();
145
+ },
146
+ });
147
+ /**
148
+ * Delete stored tokens for a connection.
149
+ */
150
+ export const deleteTokens = internalMutation({
151
+ args: { connectionId: v.id("connections") },
152
+ returns: v.null(),
153
+ handler: async (ctx, args) => {
154
+ const existing = await ctx.db
155
+ .query("providerTokens")
156
+ .withIndex("by_connectionId", (q) => q.eq("connectionId", args.connectionId))
157
+ .first();
158
+ if (existing) {
159
+ await ctx.db.delete(existing._id);
160
+ }
161
+ return null;
162
+ },
163
+ });
164
+ // ─── Activity Push Processing ───────────────────────────────────────────────
165
+ /**
166
+ * Process a Garmin activity push payload.
167
+ * Parses the full activity data, groups by user, resolves connections,
168
+ * transforms, and ingests each activity.
169
+ */
170
+ export const processActivityPushPayload = internalAction({
171
+ args: { payload: v.any() },
172
+ handler: async (ctx, args) => {
173
+ const { activities } = garminActivityPushPayloadSchema.parse(args.payload);
174
+ const items = [];
175
+ const errors = [];
176
+ // Group items by Garmin userId
177
+ const byUser = new Map();
178
+ for (const item of activities) {
179
+ const existing = byUser.get(item.userId);
180
+ if (existing) {
181
+ existing.push(item);
182
+ }
183
+ else {
184
+ byUser.set(item.userId, [item]);
185
+ }
186
+ }
187
+ for (const [garminUserId, userItems] of byUser) {
188
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
189
+ if (!connection) {
190
+ for (const item of userItems) {
191
+ errors.push({
192
+ type: "activity",
193
+ id: item.summaryId ?? "unknown",
194
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
195
+ });
196
+ }
197
+ continue;
198
+ }
199
+ if (!connection.active) {
200
+ for (const item of userItems) {
201
+ errors.push({
202
+ type: "activity",
203
+ id: item.summaryId ?? "unknown",
204
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
205
+ });
206
+ }
207
+ continue;
208
+ }
209
+ for (const item of userItems) {
210
+ try {
211
+ const data = transformActivity(item);
212
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
213
+ }
214
+ catch (err) {
215
+ errors.push({
216
+ type: "activity",
217
+ id: item.summaryId ?? "unknown",
218
+ error: err instanceof Error ? err.message : String(err),
219
+ });
220
+ }
221
+ }
222
+ }
223
+ return { items, errors };
224
+ },
225
+ });
226
+ // ─── Activity Ping Processing ──────────────────────────────────────────────
227
+ /**
228
+ * Process a Garmin activity ping payload.
229
+ * Stub — acknowledges the notification without fetching data.
230
+ */
231
+ export const processActivityPingPayload = internalAction({
232
+ args: { payload: v.any() },
233
+ handler: async (_ctx, args) => {
234
+ const { activities } = garminActivityPingPayloadSchema.parse(args.payload);
235
+ console.log(`[garmin:webhook:activities] Ping mode not yet implemented, acknowledging ${activities.length} items`);
236
+ return { processed: 0, errors: [] };
237
+ },
238
+ });
239
+ // ─── Activity Details Push Processing ─────────────────────────────────────
240
+ /**
241
+ * Process a Garmin activity details push payload.
242
+ * Parses the full activity detail data (summary + samples + laps),
243
+ * groups by user, resolves connections, transforms, and ingests each activity.
244
+ */
245
+ export const processActivityDetailsPushPayload = internalAction({
246
+ args: { payload: v.any() },
247
+ handler: async (ctx, args) => {
248
+ const { activityDetails } = garminActivityDetailsPushPayloadSchema.parse(args.payload);
249
+ const items = [];
250
+ const errors = [];
251
+ // Group items by Garmin userId
252
+ const byUser = new Map();
253
+ for (const item of activityDetails) {
254
+ const existing = byUser.get(item.userId);
255
+ if (existing) {
256
+ existing.push(item);
257
+ }
258
+ else {
259
+ byUser.set(item.userId, [item]);
260
+ }
261
+ }
262
+ for (const [garminUserId, userItems] of byUser) {
263
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
264
+ if (!connection) {
265
+ for (const item of userItems) {
266
+ errors.push({
267
+ type: "activityDetails",
268
+ id: item.summaryId ?? "unknown",
269
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
270
+ });
271
+ }
272
+ continue;
273
+ }
274
+ if (!connection.active) {
275
+ for (const item of userItems) {
276
+ errors.push({
277
+ type: "activityDetails",
278
+ id: item.summaryId ?? "unknown",
279
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
280
+ });
281
+ }
282
+ continue;
283
+ }
284
+ for (const item of userItems) {
285
+ try {
286
+ const data = transformActivityDetails(item);
287
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
288
+ }
289
+ catch (err) {
290
+ errors.push({
291
+ type: "activityDetails",
292
+ id: item.summaryId ?? "unknown",
293
+ error: err instanceof Error ? err.message : String(err),
294
+ });
295
+ }
296
+ }
297
+ }
298
+ return { items, errors };
299
+ },
300
+ });
301
+ // ─── Activity Details Ping Processing ─────────────────────────────────────
302
+ /**
303
+ * Process a Garmin activity details ping payload.
304
+ * Stub — acknowledges the notification without fetching data.
305
+ */
306
+ export const processActivityDetailsPingPayload = internalAction({
307
+ args: { payload: v.any() },
308
+ handler: async (_ctx, args) => {
309
+ const { activityDetails } = garminActivityDetailsPingPayloadSchema.parse(args.payload);
310
+ console.log(`[garmin:webhook:activityDetails] Ping mode not yet implemented, acknowledging ${activityDetails.length} items`);
311
+ return { processed: 0, errors: [] };
312
+ },
313
+ });
314
+ // ─── Manually Updated Activities Push Processing ────────────────────────────
315
+ /**
316
+ * Process a Garmin manually updated activities push payload.
317
+ * Parses the full activity data, groups by user, resolves connections,
318
+ * transforms, and ingests each activity.
319
+ */
320
+ export const processManuallyUpdatedActivitiesPushPayload = internalAction({
321
+ args: { payload: v.any() },
322
+ handler: async (ctx, args) => {
323
+ const { manuallyUpdatedActivities } = garminManuallyUpdatedActivitiesPushPayloadSchema.parse(args.payload);
324
+ const items = [];
325
+ const errors = [];
326
+ // Group items by Garmin userId
327
+ const byUser = new Map();
328
+ for (const item of manuallyUpdatedActivities) {
329
+ const existing = byUser.get(item.userId);
330
+ if (existing) {
331
+ existing.push(item);
332
+ }
333
+ else {
334
+ byUser.set(item.userId, [item]);
335
+ }
336
+ }
337
+ for (const [garminUserId, userItems] of byUser) {
338
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
339
+ if (!connection) {
340
+ for (const item of userItems) {
341
+ errors.push({
342
+ type: "manuallyUpdatedActivities",
343
+ id: item.summaryId ?? "unknown",
344
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
345
+ });
346
+ }
347
+ continue;
348
+ }
349
+ if (!connection.active) {
350
+ for (const item of userItems) {
351
+ errors.push({
352
+ type: "manuallyUpdatedActivities",
353
+ id: item.summaryId ?? "unknown",
354
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
355
+ });
356
+ }
357
+ continue;
358
+ }
359
+ for (const item of userItems) {
360
+ try {
361
+ const data = transformManuallyUpdatedActivity(item);
362
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
363
+ }
364
+ catch (err) {
365
+ errors.push({
366
+ type: "manuallyUpdatedActivities",
367
+ id: item.summaryId ?? "unknown",
368
+ error: err instanceof Error ? err.message : String(err),
369
+ });
370
+ }
371
+ }
372
+ }
373
+ return { items, errors };
374
+ },
375
+ });
376
+ // ─── Manually Updated Activities Ping Processing ────────────────────────────
377
+ /**
378
+ * Process a Garmin manually updated activities ping payload.
379
+ * Stub — acknowledges the notification without fetching data.
380
+ */
381
+ export const processManuallyUpdatedActivitiesPingPayload = internalAction({
382
+ args: { payload: v.any() },
383
+ handler: async (_ctx, args) => {
384
+ const { manuallyUpdatedActivities } = garminManuallyUpdatedActivitiesPingPayloadSchema.parse(args.payload);
385
+ console.log(`[garmin:webhook:manuallyUpdatedActivities] Ping mode not yet implemented, acknowledging ${manuallyUpdatedActivities.length} items`);
386
+ return { processed: 0, errors: [] };
387
+ },
388
+ });
389
+ // ─── Move IQ Push Processing ──────────────────────────────────────────────
390
+ /**
391
+ * Process a Garmin Move IQ push payload.
392
+ * Parses the auto-detected activity events, groups by user, resolves
393
+ * connections, transforms, and ingests each event as an activity.
394
+ */
395
+ export const processMoveIQPushPayload = internalAction({
396
+ args: { payload: v.any() },
397
+ handler: async (ctx, args) => {
398
+ const { moveIQActivities } = garminMoveIQPushPayloadSchema.parse(args.payload);
399
+ const items = [];
400
+ const errors = [];
401
+ // Group items by Garmin userId
402
+ const byUser = new Map();
403
+ for (const item of moveIQActivities) {
404
+ const existing = byUser.get(item.userId);
405
+ if (existing) {
406
+ existing.push(item);
407
+ }
408
+ else {
409
+ byUser.set(item.userId, [item]);
410
+ }
411
+ }
412
+ for (const [garminUserId, userItems] of byUser) {
413
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
414
+ if (!connection) {
415
+ for (const item of userItems) {
416
+ errors.push({
417
+ type: "moveIQ",
418
+ id: item.summaryId ?? "unknown",
419
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
420
+ });
421
+ }
422
+ continue;
423
+ }
424
+ if (!connection.active) {
425
+ for (const item of userItems) {
426
+ errors.push({
427
+ type: "moveIQ",
428
+ id: item.summaryId ?? "unknown",
429
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
430
+ });
431
+ }
432
+ continue;
433
+ }
434
+ for (const item of userItems) {
435
+ try {
436
+ const data = transformMoveIQ(item);
437
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
438
+ }
439
+ catch (err) {
440
+ errors.push({
441
+ type: "moveIQ",
442
+ id: item.summaryId ?? "unknown",
443
+ error: err instanceof Error ? err.message : String(err),
444
+ });
445
+ }
446
+ }
447
+ }
448
+ return { items, errors };
449
+ },
450
+ });
451
+ // ─── Move IQ Ping Processing ─────────────────────────────────────────────
452
+ /**
453
+ * Process a Garmin Move IQ ping payload.
454
+ * Stub — acknowledges the notification without fetching data.
455
+ */
456
+ export const processMoveIQPingPayload = internalAction({
457
+ args: { payload: v.any() },
458
+ handler: async (_ctx, args) => {
459
+ const { moveIQActivities } = garminMoveIQPingPayloadSchema.parse(args.payload);
460
+ console.log(`[garmin:webhook:moveIQ] Ping mode not yet implemented, acknowledging ${moveIQActivities.length} items`);
461
+ return { processed: 0, errors: [] };
462
+ },
463
+ });
464
+ // ─── Blood Pressure Push Processing ─────────────────────────────────────────
465
+ /**
466
+ * Process a Garmin blood pressure push payload.
467
+ * Parses the full blood pressure data, groups by user, resolves connections,
468
+ * transforms, and ingests each record into the body table.
469
+ */
470
+ export const processBloodPressurePushPayload = internalAction({
471
+ args: { payload: v.any() },
472
+ handler: async (ctx, args) => {
473
+ const { bloodPressures } = garminBloodPressurePushPayloadSchema.parse(args.payload);
474
+ const items = [];
475
+ const errors = [];
476
+ // Group items by Garmin userId
477
+ const byUser = new Map();
478
+ for (const item of bloodPressures) {
479
+ const existing = byUser.get(item.userId);
480
+ if (existing) {
481
+ existing.push(item);
482
+ }
483
+ else {
484
+ byUser.set(item.userId, [item]);
485
+ }
486
+ }
487
+ for (const [garminUserId, userItems] of byUser) {
488
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
489
+ if (!connection) {
490
+ for (const item of userItems) {
491
+ errors.push({
492
+ type: "bloodPressure",
493
+ id: item.summaryId ?? "unknown",
494
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
495
+ });
496
+ }
497
+ continue;
498
+ }
499
+ if (!connection.active) {
500
+ for (const item of userItems) {
501
+ errors.push({
502
+ type: "bloodPressure",
503
+ id: item.summaryId ?? "unknown",
504
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
505
+ });
506
+ }
507
+ continue;
508
+ }
509
+ for (const item of userItems) {
510
+ try {
511
+ const data = transformBloodPressure(item);
512
+ if (data == null)
513
+ continue;
514
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
515
+ }
516
+ catch (err) {
517
+ errors.push({
518
+ type: "bloodPressure",
519
+ id: item.summaryId ?? "unknown",
520
+ error: err instanceof Error ? err.message : String(err),
521
+ });
522
+ }
523
+ }
524
+ }
525
+ return { items, errors };
526
+ },
527
+ });
528
+ // ─── Blood Pressure Ping Processing ─────────────────────────────────────────
529
+ /**
530
+ * Process a Garmin blood pressure ping payload.
531
+ * Stub — acknowledges the notification without fetching data.
532
+ */
533
+ export const processBloodPressurePingPayload = internalAction({
534
+ args: { payload: v.any() },
535
+ handler: async (_ctx, args) => {
536
+ const { bloodPressures } = garminBloodPressurePingPayloadSchema.parse(args.payload);
537
+ console.log(`[garmin:webhook:bloodPressures] Ping mode not yet implemented, acknowledging ${bloodPressures.length} items`);
538
+ return { processed: 0, errors: [] };
539
+ },
540
+ });
541
+ // ─── Body Compositions Push Processing ─────────────────────────────────────
542
+ /**
543
+ * Process a Garmin body compositions push payload.
544
+ * Parses the full body composition data, groups by user, resolves connections,
545
+ * transforms, and ingests each record into the body table.
546
+ */
547
+ export const processBodyCompositionsPushPayload = internalAction({
548
+ args: { payload: v.any() },
549
+ handler: async (ctx, args) => {
550
+ const { bodyComps } = garminBodyCompositionsPushPayloadSchema.parse(args.payload);
551
+ const items = [];
552
+ const errors = [];
553
+ // Group items by Garmin userId
554
+ const byUser = new Map();
555
+ for (const item of bodyComps) {
556
+ const existing = byUser.get(item.userId);
557
+ if (existing) {
558
+ existing.push(item);
559
+ }
560
+ else {
561
+ byUser.set(item.userId, [item]);
562
+ }
563
+ }
564
+ for (const [garminUserId, userItems] of byUser) {
565
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
566
+ if (!connection) {
567
+ for (const item of userItems) {
568
+ errors.push({
569
+ type: "bodyCompositions",
570
+ id: item.summaryId ?? "unknown",
571
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
572
+ });
573
+ }
574
+ continue;
575
+ }
576
+ if (!connection.active) {
577
+ for (const item of userItems) {
578
+ errors.push({
579
+ type: "bodyCompositions",
580
+ id: item.summaryId ?? "unknown",
581
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
582
+ });
583
+ }
584
+ continue;
585
+ }
586
+ for (const item of userItems) {
587
+ try {
588
+ const data = transformBodyComposition(item);
589
+ if (data == null)
590
+ continue;
591
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
592
+ }
593
+ catch (err) {
594
+ errors.push({
595
+ type: "bodyCompositions",
596
+ id: item.summaryId ?? "unknown",
597
+ error: err instanceof Error ? err.message : String(err),
598
+ });
599
+ }
600
+ }
601
+ }
602
+ return { items, errors };
603
+ },
604
+ });
605
+ // ─── Body Compositions Ping Processing ─────────────────────────────────────
606
+ /**
607
+ * Process a Garmin body compositions ping payload.
608
+ * Stub — acknowledges the notification without fetching data.
609
+ */
610
+ export const processBodyCompositionsPingPayload = internalAction({
611
+ args: { payload: v.any() },
612
+ handler: async (_ctx, args) => {
613
+ const { bodyComps } = garminBodyCompositionsPingPayloadSchema.parse(args.payload);
614
+ console.log(`[garmin:webhook:bodyCompositions] Ping mode not yet implemented, acknowledging ${bodyComps.length} items`);
615
+ return { processed: 0, errors: [] };
616
+ },
617
+ });
618
+ // ─── Dailies Push Processing ──────────────────────────────────────────────
619
+ /**
620
+ * Process a Garmin dailies push payload.
621
+ * Parses the full daily summary data, groups by user, resolves connections,
622
+ * transforms, and ingests each record into the daily table.
623
+ */
624
+ export const processDailiesPushPayload = internalAction({
625
+ args: { payload: v.any() },
626
+ handler: async (ctx, args) => {
627
+ const { dailies } = garminDailiesPushPayloadSchema.parse(args.payload);
628
+ const items = [];
629
+ const errors = [];
630
+ // Group items by Garmin userId
631
+ const byUser = new Map();
632
+ for (const item of dailies) {
633
+ const existing = byUser.get(item.userId);
634
+ if (existing) {
635
+ existing.push(item);
636
+ }
637
+ else {
638
+ byUser.set(item.userId, [item]);
639
+ }
640
+ }
641
+ for (const [garminUserId, userItems] of byUser) {
642
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
643
+ if (!connection) {
644
+ for (const item of userItems) {
645
+ errors.push({
646
+ type: "dailies",
647
+ id: item.summaryId ?? "unknown",
648
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
649
+ });
650
+ }
651
+ continue;
652
+ }
653
+ if (!connection.active) {
654
+ for (const item of userItems) {
655
+ errors.push({
656
+ type: "dailies",
657
+ id: item.summaryId ?? "unknown",
658
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
659
+ });
660
+ }
661
+ continue;
662
+ }
663
+ for (const item of userItems) {
664
+ try {
665
+ const data = transformDailies(item);
666
+ if (data == null)
667
+ continue;
668
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
669
+ }
670
+ catch (err) {
671
+ errors.push({
672
+ type: "dailies",
673
+ id: item.summaryId ?? "unknown",
674
+ error: err instanceof Error ? err.message : String(err),
675
+ });
676
+ }
677
+ }
678
+ }
679
+ return { items, errors };
680
+ },
681
+ });
682
+ // ─── Dailies Ping Processing ──────────────────────────────────────────────
683
+ /**
684
+ * Process a Garmin dailies ping payload.
685
+ * Stub — acknowledges the notification without fetching data.
686
+ */
687
+ export const processDailiesPingPayload = internalAction({
688
+ args: { payload: v.any() },
689
+ handler: async (_ctx, args) => {
690
+ const { dailies } = garminDailiesPingPayloadSchema.parse(args.payload);
691
+ console.log(`[garmin:webhook:dailies] Ping mode not yet implemented, acknowledging ${dailies.length} items`);
692
+ return { processed: 0, errors: [] };
693
+ },
694
+ });
695
+ // ─── Health Snapshot Push Processing ────────────────────────────────────────
696
+ /**
697
+ * Process a Garmin health snapshot push payload.
698
+ * Parses the full health snapshot data, groups by user, resolves connections,
699
+ * transforms, and ingests each record into the daily table.
700
+ */
701
+ export const processHealthSnapshotPushPayload = internalAction({
702
+ args: { payload: v.any() },
703
+ handler: async (ctx, args) => {
704
+ const { healthSnapshot } = garminHealthSnapshotPushPayloadSchema.parse(args.payload);
705
+ const items = [];
706
+ const errors = [];
707
+ // Group items by Garmin userId
708
+ const byUser = new Map();
709
+ for (const item of healthSnapshot) {
710
+ const existing = byUser.get(item.userId);
711
+ if (existing) {
712
+ existing.push(item);
713
+ }
714
+ else {
715
+ byUser.set(item.userId, [item]);
716
+ }
717
+ }
718
+ for (const [garminUserId, userItems] of byUser) {
719
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
720
+ if (!connection) {
721
+ for (const item of userItems) {
722
+ errors.push({
723
+ type: "healthSnapshot",
724
+ id: item.summaryId ?? "unknown",
725
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
726
+ });
727
+ }
728
+ continue;
729
+ }
730
+ if (!connection.active) {
731
+ for (const item of userItems) {
732
+ errors.push({
733
+ type: "healthSnapshot",
734
+ id: item.summaryId ?? "unknown",
735
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
736
+ });
737
+ }
738
+ continue;
739
+ }
740
+ for (const item of userItems) {
741
+ try {
742
+ const data = transformHealthSnapshot(item);
743
+ if (data == null)
744
+ continue;
745
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
746
+ }
747
+ catch (err) {
748
+ errors.push({
749
+ type: "healthSnapshot",
750
+ id: item.summaryId ?? "unknown",
751
+ error: err instanceof Error ? err.message : String(err),
752
+ });
753
+ }
754
+ }
755
+ }
756
+ return { items, errors };
757
+ },
758
+ });
759
+ // ─── Health Snapshot Ping Processing ────────────────────────────────────────
760
+ /**
761
+ * Process a Garmin health snapshot ping payload.
762
+ * Stub — acknowledges the notification without fetching data.
763
+ */
764
+ export const processHealthSnapshotPingPayload = internalAction({
765
+ args: { payload: v.any() },
766
+ handler: async (_ctx, args) => {
767
+ const { healthSnapshot } = garminHealthSnapshotPingPayloadSchema.parse(args.payload);
768
+ console.log(`[garmin:webhook:healthSnapshot] Ping mode not yet implemented, acknowledging ${healthSnapshot.length} items`);
769
+ return { processed: 0, errors: [] };
770
+ },
771
+ });
772
+ // ─── HRV Summary Push Processing ────────────────────────────────────────────
773
+ /**
774
+ * Process a Garmin HRV summary push payload.
775
+ * Parses the full HRV summary data, groups by user, resolves connections,
776
+ * transforms, and ingests each record into the daily table.
777
+ */
778
+ export const processHRVSummaryPushPayload = internalAction({
779
+ args: { payload: v.any() },
780
+ handler: async (ctx, args) => {
781
+ const { hrv } = garminHRVSummaryPushPayloadSchema.parse(args.payload);
782
+ const items = [];
783
+ const errors = [];
784
+ // Group items by Garmin userId
785
+ const byUser = new Map();
786
+ for (const item of hrv) {
787
+ const existing = byUser.get(item.userId);
788
+ if (existing) {
789
+ existing.push(item);
790
+ }
791
+ else {
792
+ byUser.set(item.userId, [item]);
793
+ }
794
+ }
795
+ for (const [garminUserId, userItems] of byUser) {
796
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
797
+ if (!connection) {
798
+ for (const item of userItems) {
799
+ errors.push({
800
+ type: "hrvSummary",
801
+ id: item.summaryId ?? "unknown",
802
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
803
+ });
804
+ }
805
+ continue;
806
+ }
807
+ if (!connection.active) {
808
+ for (const item of userItems) {
809
+ errors.push({
810
+ type: "hrvSummary",
811
+ id: item.summaryId ?? "unknown",
812
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
813
+ });
814
+ }
815
+ continue;
816
+ }
817
+ for (const item of userItems) {
818
+ try {
819
+ const data = transformHRVSummary(item);
820
+ if (data == null)
821
+ continue;
822
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
823
+ }
824
+ catch (err) {
825
+ errors.push({
826
+ type: "hrvSummary",
827
+ id: item.summaryId ?? "unknown",
828
+ error: err instanceof Error ? err.message : String(err),
829
+ });
830
+ }
831
+ }
832
+ }
833
+ return { items, errors };
834
+ },
835
+ });
836
+ // ─── HRV Summary Ping Processing ────────────────────────────────────────────
837
+ /**
838
+ * Process a Garmin HRV summary ping payload.
839
+ * Stub — acknowledges the notification without fetching data.
840
+ */
841
+ export const processHRVSummaryPingPayload = internalAction({
842
+ args: { payload: v.any() },
843
+ handler: async (_ctx, args) => {
844
+ const { hrv } = garminHRVSummaryPingPayloadSchema.parse(args.payload);
845
+ console.log(`[garmin:webhook:hrvSummary] Ping mode not yet implemented, acknowledging ${hrv.length} items`);
846
+ return { processed: 0, errors: [] };
847
+ },
848
+ });
849
+ // ─── Epoch Push Processing ──────────────────────────────────────────────────
850
+ /**
851
+ * Process a Garmin epoch push payload.
852
+ * Parses the full epoch summary data (15-min wellness slices), groups by user,
853
+ * resolves connections, transforms, and ingests each record into the daily table.
854
+ */
855
+ export const processEpochPushPayload = internalAction({
856
+ args: { payload: v.any() },
857
+ handler: async (ctx, args) => {
858
+ const { epochs } = garminEpochPushPayloadSchema.parse(args.payload);
859
+ const items = [];
860
+ const errors = [];
861
+ // Group items by Garmin userId
862
+ const byUser = new Map();
863
+ for (const item of epochs) {
864
+ const existing = byUser.get(item.userId);
865
+ if (existing) {
866
+ existing.push(item);
867
+ }
868
+ else {
869
+ byUser.set(item.userId, [item]);
870
+ }
871
+ }
872
+ for (const [garminUserId, userItems] of byUser) {
873
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
874
+ if (!connection) {
875
+ for (const item of userItems) {
876
+ errors.push({
877
+ type: "epochs",
878
+ id: item.summaryId ?? "unknown",
879
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
880
+ });
881
+ }
882
+ continue;
883
+ }
884
+ if (!connection.active) {
885
+ for (const item of userItems) {
886
+ errors.push({
887
+ type: "epochs",
888
+ id: item.summaryId ?? "unknown",
889
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
890
+ });
891
+ }
892
+ continue;
893
+ }
894
+ for (const item of userItems) {
895
+ try {
896
+ const data = transformEpoch(item);
897
+ if (data == null)
898
+ continue;
899
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
900
+ }
901
+ catch (err) {
902
+ errors.push({
903
+ type: "epochs",
904
+ id: item.summaryId ?? "unknown",
905
+ error: err instanceof Error ? err.message : String(err),
906
+ });
907
+ }
908
+ }
909
+ }
910
+ return { items, errors };
911
+ },
912
+ });
913
+ // ─── Epoch Ping Processing ──────────────────────────────────────────────────
914
+ /**
915
+ * Process a Garmin epoch ping payload.
916
+ * Stub — acknowledges the notification without fetching data.
917
+ */
918
+ export const processEpochPingPayload = internalAction({
919
+ args: { payload: v.any() },
920
+ handler: async (_ctx, args) => {
921
+ const { epochs } = garminEpochPingPayloadSchema.parse(args.payload);
922
+ console.log(`[garmin:webhook:epochs] Ping mode not yet implemented, acknowledging ${epochs.length} items`);
923
+ return { processed: 0, errors: [] };
924
+ },
925
+ });
926
+ // ─── Pulse Ox Push Processing ──────────────────────────────────────────────
927
+ /**
928
+ * Process a Garmin Pulse Ox push payload.
929
+ * Parses the full SpO2 data, groups by user, resolves connections,
930
+ * transforms, and ingests each record into the daily table.
931
+ */
932
+ export const processPulseOxPushPayload = internalAction({
933
+ args: { payload: v.any() },
934
+ handler: async (ctx, args) => {
935
+ const { pulseox } = garminPulseOxPushPayloadSchema.parse(args.payload);
936
+ const items = [];
937
+ const errors = [];
938
+ // Group items by Garmin userId
939
+ const byUser = new Map();
940
+ for (const item of pulseox) {
941
+ const existing = byUser.get(item.userId);
942
+ if (existing) {
943
+ existing.push(item);
944
+ }
945
+ else {
946
+ byUser.set(item.userId, [item]);
947
+ }
948
+ }
949
+ for (const [garminUserId, userItems] of byUser) {
950
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
951
+ if (!connection) {
952
+ for (const item of userItems) {
953
+ errors.push({
954
+ type: "pulseOx",
955
+ id: item.summaryId ?? "unknown",
956
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
957
+ });
958
+ }
959
+ continue;
960
+ }
961
+ if (!connection.active) {
962
+ for (const item of userItems) {
963
+ errors.push({
964
+ type: "pulseOx",
965
+ id: item.summaryId ?? "unknown",
966
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
967
+ });
968
+ }
969
+ continue;
970
+ }
971
+ for (const item of userItems) {
972
+ try {
973
+ const data = transformPulseOx(item);
974
+ if (data == null)
975
+ continue;
976
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
977
+ }
978
+ catch (err) {
979
+ errors.push({
980
+ type: "pulseOx",
981
+ id: item.summaryId ?? "unknown",
982
+ error: err instanceof Error ? err.message : String(err),
983
+ });
984
+ }
985
+ }
986
+ }
987
+ return { items, errors };
988
+ },
989
+ });
990
+ // ─── Pulse Ox Ping Processing ──────────────────────────────────────────────
991
+ /**
992
+ * Process a Garmin Pulse Ox ping payload.
993
+ * Stub — acknowledges the notification without fetching data.
994
+ */
995
+ export const processPulseOxPingPayload = internalAction({
996
+ args: { payload: v.any() },
997
+ handler: async (_ctx, args) => {
998
+ const { pulseox } = garminPulseOxPingPayloadSchema.parse(args.payload);
999
+ console.log(`[garmin:webhook:pulseOx] Ping mode not yet implemented, acknowledging ${pulseox.length} items`);
1000
+ return { processed: 0, errors: [] };
1001
+ },
1002
+ });
1003
+ // ─── Respiration Push Processing ──────────────────────────────────────────
1004
+ /**
1005
+ * Process a Garmin Respiration push payload.
1006
+ * Parses the full breathing rate data, groups by user, resolves connections,
1007
+ * transforms, and ingests each record into the daily table.
1008
+ */
1009
+ export const processRespirationPushPayload = internalAction({
1010
+ args: { payload: v.any() },
1011
+ handler: async (ctx, args) => {
1012
+ const { allDayRespiration } = garminRespirationPushPayloadSchema.parse(args.payload);
1013
+ const items = [];
1014
+ const errors = [];
1015
+ // Group items by Garmin userId
1016
+ const byUser = new Map();
1017
+ for (const item of allDayRespiration) {
1018
+ const existing = byUser.get(item.userId);
1019
+ if (existing) {
1020
+ existing.push(item);
1021
+ }
1022
+ else {
1023
+ byUser.set(item.userId, [item]);
1024
+ }
1025
+ }
1026
+ for (const [garminUserId, userItems] of byUser) {
1027
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
1028
+ if (!connection) {
1029
+ for (const item of userItems) {
1030
+ errors.push({
1031
+ type: "respiration",
1032
+ id: item.summaryId ?? "unknown",
1033
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
1034
+ });
1035
+ }
1036
+ continue;
1037
+ }
1038
+ if (!connection.active) {
1039
+ for (const item of userItems) {
1040
+ errors.push({
1041
+ type: "respiration",
1042
+ id: item.summaryId ?? "unknown",
1043
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
1044
+ });
1045
+ }
1046
+ continue;
1047
+ }
1048
+ for (const item of userItems) {
1049
+ try {
1050
+ const data = transformRespiration(item);
1051
+ if (data == null)
1052
+ continue;
1053
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
1054
+ }
1055
+ catch (err) {
1056
+ errors.push({
1057
+ type: "respiration",
1058
+ id: item.summaryId ?? "unknown",
1059
+ error: err instanceof Error ? err.message : String(err),
1060
+ });
1061
+ }
1062
+ }
1063
+ }
1064
+ return { items, errors };
1065
+ },
1066
+ });
1067
+ // ─── Respiration Ping Processing ──────────────────────────────────────────
1068
+ /**
1069
+ * Process a Garmin Respiration ping payload.
1070
+ * Stub — acknowledges the notification without fetching data.
1071
+ */
1072
+ export const processRespirationPingPayload = internalAction({
1073
+ args: { payload: v.any() },
1074
+ handler: async (_ctx, args) => {
1075
+ const { allDayRespiration } = garminRespirationPingPayloadSchema.parse(args.payload);
1076
+ console.log(`[garmin:webhook:respiration] Ping mode not yet implemented, acknowledging ${allDayRespiration.length} items`);
1077
+ return { processed: 0, errors: [] };
1078
+ },
1079
+ });
1080
+ // ─── Stress Details Push Processing ──────────────────────────────────────────
1081
+ /**
1082
+ * Process a Garmin stress details push payload.
1083
+ * Parses the full stress data, groups by user, resolves connections,
1084
+ * transforms, and ingests each record into the daily table.
1085
+ */
1086
+ export const processStressPushPayload = internalAction({
1087
+ args: { payload: v.any() },
1088
+ handler: async (ctx, args) => {
1089
+ const { stressDetails } = garminStressPushPayloadSchema.parse(args.payload);
1090
+ const items = [];
1091
+ const errors = [];
1092
+ // Group items by Garmin userId
1093
+ const byUser = new Map();
1094
+ for (const item of stressDetails) {
1095
+ const existing = byUser.get(item.userId);
1096
+ if (existing) {
1097
+ existing.push(item);
1098
+ }
1099
+ else {
1100
+ byUser.set(item.userId, [item]);
1101
+ }
1102
+ }
1103
+ for (const [garminUserId, userItems] of byUser) {
1104
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
1105
+ if (!connection) {
1106
+ for (const item of userItems) {
1107
+ errors.push({
1108
+ type: "stressDetails",
1109
+ id: item.summaryId ?? "unknown",
1110
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
1111
+ });
1112
+ }
1113
+ continue;
1114
+ }
1115
+ if (!connection.active) {
1116
+ for (const item of userItems) {
1117
+ errors.push({
1118
+ type: "stressDetails",
1119
+ id: item.summaryId ?? "unknown",
1120
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
1121
+ });
1122
+ }
1123
+ continue;
1124
+ }
1125
+ for (const item of userItems) {
1126
+ try {
1127
+ const data = transformStress(item);
1128
+ if (data == null)
1129
+ continue;
1130
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
1131
+ }
1132
+ catch (err) {
1133
+ errors.push({
1134
+ type: "stressDetails",
1135
+ id: item.summaryId ?? "unknown",
1136
+ error: err instanceof Error ? err.message : String(err),
1137
+ });
1138
+ }
1139
+ }
1140
+ }
1141
+ return { items, errors };
1142
+ },
1143
+ });
1144
+ // ─── Stress Details Ping Processing ─────────────────────────────────────────
1145
+ /**
1146
+ * Process a Garmin stress details ping payload.
1147
+ * Stub — acknowledges the notification without fetching data.
1148
+ */
1149
+ export const processStressPingPayload = internalAction({
1150
+ args: { payload: v.any() },
1151
+ handler: async (_ctx, args) => {
1152
+ const { stressDetails } = garminStressPingPayloadSchema.parse(args.payload);
1153
+ console.log(`[garmin:webhook:stressDetails] Ping mode not yet implemented, acknowledging ${stressDetails.length} items`);
1154
+ return { processed: 0, errors: [] };
1155
+ },
1156
+ });
1157
+ // ─── Skin Temperature Push Processing ───────────────────────────────────────
1158
+ /**
1159
+ * Process a Garmin skin temperature push payload.
1160
+ * Parses the full skin temperature data, groups by user, resolves connections,
1161
+ * transforms, and ingests each record into the body table.
1162
+ */
1163
+ export const processSkinTemperaturePushPayload = internalAction({
1164
+ args: { payload: v.any() },
1165
+ handler: async (ctx, args) => {
1166
+ const { skinTemp } = garminSkinTemperaturePushPayloadSchema.parse(args.payload);
1167
+ const items = [];
1168
+ const errors = [];
1169
+ // Group items by Garmin userId
1170
+ const byUser = new Map();
1171
+ for (const item of skinTemp) {
1172
+ const existing = byUser.get(item.userId);
1173
+ if (existing) {
1174
+ existing.push(item);
1175
+ }
1176
+ else {
1177
+ byUser.set(item.userId, [item]);
1178
+ }
1179
+ }
1180
+ for (const [garminUserId, userItems] of byUser) {
1181
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
1182
+ if (!connection) {
1183
+ for (const item of userItems) {
1184
+ errors.push({
1185
+ type: "skinTemperature",
1186
+ id: item.summaryId ?? "unknown",
1187
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
1188
+ });
1189
+ }
1190
+ continue;
1191
+ }
1192
+ if (!connection.active) {
1193
+ for (const item of userItems) {
1194
+ errors.push({
1195
+ type: "skinTemperature",
1196
+ id: item.summaryId ?? "unknown",
1197
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
1198
+ });
1199
+ }
1200
+ continue;
1201
+ }
1202
+ for (const item of userItems) {
1203
+ try {
1204
+ const data = transformSkinTemperature(item);
1205
+ if (data == null)
1206
+ continue;
1207
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
1208
+ }
1209
+ catch (err) {
1210
+ errors.push({
1211
+ type: "skinTemperature",
1212
+ id: item.summaryId ?? "unknown",
1213
+ error: err instanceof Error ? err.message : String(err),
1214
+ });
1215
+ }
1216
+ }
1217
+ }
1218
+ return { items, errors };
1219
+ },
1220
+ });
1221
+ // ─── Skin Temperature Ping Processing ───────────────────────────────────────
1222
+ /**
1223
+ * Process a Garmin skin temperature ping payload.
1224
+ * Stub — acknowledges the notification without fetching data.
1225
+ */
1226
+ export const processSkinTemperaturePingPayload = internalAction({
1227
+ args: { payload: v.any() },
1228
+ handler: async (_ctx, args) => {
1229
+ const { skinTemp } = garminSkinTemperaturePingPayloadSchema.parse(args.payload);
1230
+ console.log(`[garmin:webhook:skinTemperature] Ping mode not yet implemented, acknowledging ${skinTemp.length} items`);
1231
+ return { processed: 0, errors: [] };
1232
+ },
1233
+ });
1234
+ // ─── Sleeps Push Processing ─────────────────────────────────────────────────
1235
+ /**
1236
+ * Process a Garmin sleep summary push payload.
1237
+ * Parses the full sleep data, groups by user, resolves connections,
1238
+ * transforms, and ingests each sleep record.
1239
+ */
1240
+ export const processSleepsPushPayload = internalAction({
1241
+ args: { payload: v.any() },
1242
+ handler: async (ctx, args) => {
1243
+ const { sleeps } = garminSleepsPushPayloadSchema.parse(args.payload);
1244
+ const items = [];
1245
+ const errors = [];
1246
+ // Group items by Garmin userId
1247
+ const byUser = new Map();
1248
+ for (const item of sleeps) {
1249
+ const existing = byUser.get(item.userId);
1250
+ if (existing) {
1251
+ existing.push(item);
1252
+ }
1253
+ else {
1254
+ byUser.set(item.userId, [item]);
1255
+ }
1256
+ }
1257
+ for (const [garminUserId, userItems] of byUser) {
1258
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
1259
+ if (!connection) {
1260
+ for (const item of userItems) {
1261
+ errors.push({
1262
+ type: "sleep",
1263
+ id: item.summaryId ?? "unknown",
1264
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
1265
+ });
1266
+ }
1267
+ continue;
1268
+ }
1269
+ if (!connection.active) {
1270
+ for (const item of userItems) {
1271
+ errors.push({
1272
+ type: "sleep",
1273
+ id: item.summaryId ?? "unknown",
1274
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
1275
+ });
1276
+ }
1277
+ continue;
1278
+ }
1279
+ for (const item of userItems) {
1280
+ try {
1281
+ const data = transformSleeps(item);
1282
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
1283
+ }
1284
+ catch (err) {
1285
+ errors.push({
1286
+ type: "sleep",
1287
+ id: item.summaryId ?? "unknown",
1288
+ error: err instanceof Error ? err.message : String(err),
1289
+ });
1290
+ }
1291
+ }
1292
+ }
1293
+ return { items, errors };
1294
+ },
1295
+ });
1296
+ // ─── Sleeps Ping Processing ─────────────────────────────────────────────────
1297
+ /**
1298
+ * Process a Garmin sleep summary ping payload.
1299
+ * Stub — acknowledges the notification without fetching data.
1300
+ */
1301
+ export const processSleepsPingPayload = internalAction({
1302
+ args: { payload: v.any() },
1303
+ handler: async (_ctx, args) => {
1304
+ const { sleeps } = garminSleepsPingPayloadSchema.parse(args.payload);
1305
+ console.log(`[garmin:webhook:sleeps] Ping mode not yet implemented, acknowledging ${sleeps.length} items`);
1306
+ return { processed: 0, errors: [] };
1307
+ },
1308
+ });
1309
+ // ─── User Metrics Push Processing ──────────────────────────────────────────
1310
+ /**
1311
+ * Process a Garmin user metrics push payload.
1312
+ * Parses the full user metrics data, groups by user, resolves connections,
1313
+ * transforms, and ingests each user metrics record.
1314
+ */
1315
+ export const processUserMetricsPushPayload = internalAction({
1316
+ args: { payload: v.any() },
1317
+ handler: async (ctx, args) => {
1318
+ const { userMetrics } = garminUserMetricsPushPayloadSchema.parse(args.payload);
1319
+ const items = [];
1320
+ const errors = [];
1321
+ // Group items by Garmin userId
1322
+ const byUser = new Map();
1323
+ for (const item of userMetrics) {
1324
+ const existing = byUser.get(item.userId);
1325
+ if (existing) {
1326
+ existing.push(item);
1327
+ }
1328
+ else {
1329
+ byUser.set(item.userId, [item]);
1330
+ }
1331
+ }
1332
+ for (const [garminUserId, userItems] of byUser) {
1333
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
1334
+ if (!connection) {
1335
+ for (const item of userItems) {
1336
+ errors.push({
1337
+ type: "userMetrics",
1338
+ id: item.summaryId ?? "unknown",
1339
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
1340
+ });
1341
+ }
1342
+ continue;
1343
+ }
1344
+ if (!connection.active) {
1345
+ for (const item of userItems) {
1346
+ errors.push({
1347
+ type: "userMetrics",
1348
+ id: item.summaryId ?? "unknown",
1349
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
1350
+ });
1351
+ }
1352
+ continue;
1353
+ }
1354
+ for (const item of userItems) {
1355
+ try {
1356
+ const data = transformUserMetrics(item);
1357
+ if (data == null)
1358
+ continue;
1359
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
1360
+ }
1361
+ catch (err) {
1362
+ errors.push({
1363
+ type: "userMetrics",
1364
+ id: item.summaryId ?? "unknown",
1365
+ error: err instanceof Error ? err.message : String(err),
1366
+ });
1367
+ }
1368
+ }
1369
+ }
1370
+ return { items, errors };
1371
+ },
1372
+ });
1373
+ // ─── User Metrics Ping Processing ──────────────────────────────────────────
1374
+ /**
1375
+ * Process a Garmin user metrics ping payload.
1376
+ * Stub — acknowledges the notification without fetching data.
1377
+ */
1378
+ export const processUserMetricsPingPayload = internalAction({
1379
+ args: { payload: v.any() },
1380
+ handler: async (_ctx, args) => {
1381
+ const { userMetrics } = garminUserMetricsPingPayloadSchema.parse(args.payload);
1382
+ console.log(`[garmin:webhook:userMetrics] Ping mode not yet implemented, acknowledging ${userMetrics.length} items`);
1383
+ return { processed: 0, errors: [] };
1384
+ },
1385
+ });
1386
+ // ─── Menstrual Cycle Tracking Push Processing ───────────────────────────────
1387
+ /**
1388
+ * Process a Garmin MCT (Women's Health API) push payload.
1389
+ * Parses full MCT summary data, groups by user, resolves connections,
1390
+ * transforms, and ingests each record into the menstruation table.
1391
+ */
1392
+ export const processMenstrualCycleTrackingPushPayload = internalAction({
1393
+ args: { payload: v.any() },
1394
+ handler: async (ctx, args) => {
1395
+ const { mct } = garminMenstrualCycleTrackingPushPayloadSchema.parse(args.payload);
1396
+ const items = [];
1397
+ const errors = [];
1398
+ // Group items by Garmin userId
1399
+ const byUser = new Map();
1400
+ for (const item of mct) {
1401
+ const existing = byUser.get(item.userId);
1402
+ if (existing) {
1403
+ existing.push(item);
1404
+ }
1405
+ else {
1406
+ byUser.set(item.userId, [item]);
1407
+ }
1408
+ }
1409
+ for (const [garminUserId, userItems] of byUser) {
1410
+ const connection = await ctx.runQuery(internal.private.getConnectionByProviderUserId, { providerUserId: garminUserId, provider: "GARMIN" });
1411
+ if (!connection) {
1412
+ for (const item of userItems) {
1413
+ errors.push({
1414
+ type: "menstrualCycleTracking",
1415
+ id: item.summaryId ?? "unknown",
1416
+ error: `No Soma connection found for Garmin userId "${garminUserId}"`,
1417
+ });
1418
+ }
1419
+ continue;
1420
+ }
1421
+ if (!connection.active) {
1422
+ for (const item of userItems) {
1423
+ errors.push({
1424
+ type: "menstrualCycleTracking",
1425
+ id: item.summaryId ?? "unknown",
1426
+ error: `Garmin connection for userId "${garminUserId}" is inactive`,
1427
+ });
1428
+ }
1429
+ continue;
1430
+ }
1431
+ for (const item of userItems) {
1432
+ try {
1433
+ const data = transformMenstrualCycleTracking(item);
1434
+ items.push({ connectionId: connection._id, userId: connection.userId, data });
1435
+ }
1436
+ catch (err) {
1437
+ errors.push({
1438
+ type: "menstrualCycleTracking",
1439
+ id: item.summaryId ?? "unknown",
1440
+ error: err instanceof Error ? err.message : String(err),
1441
+ });
1442
+ }
1443
+ }
1444
+ }
1445
+ return { items, errors };
1446
+ },
1447
+ });
1448
+ // ─── Menstrual Cycle Tracking Ping Processing ───────────────────────────────
1449
+ /**
1450
+ * Process a Garmin MCT ping payload.
1451
+ * Stub — acknowledges the notification without fetching data.
1452
+ */
1453
+ export const processMenstrualCycleTrackingPingPayload = internalAction({
1454
+ args: { payload: v.any() },
1455
+ handler: async (_ctx, args) => {
1456
+ const { mct } = garminMenstrualCycleTrackingPingPayloadSchema.parse(args.payload);
1457
+ console.log(`[garmin:webhook:menstrualCycleTracking] Ping mode not yet implemented, acknowledging ${mct.length} items`);
1458
+ return { processed: 0, errors: [] };
1459
+ },
1460
+ });
1461
+ //# sourceMappingURL=private.js.map