@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.
Files changed (390) hide show
  1. package/dist/client/index.d.ts +17 -55
  2. package/dist/client/index.d.ts.map +1 -1
  3. package/dist/client/index.js +63 -13
  4. package/dist/client/index.js.map +1 -1
  5. package/dist/component/_generated/api.d.ts +80 -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 +153 -120
  9. package/dist/component/_generated/component.d.ts.map +1 -1
  10. package/dist/component/garmin/private.d.ts +475 -0
  11. package/dist/component/garmin/private.d.ts.map +1 -0
  12. package/dist/component/garmin/private.js +1614 -0
  13. package/dist/component/garmin/private.js.map +1 -0
  14. package/dist/component/{garmin.d.ts → garmin/public.d.ts} +25 -52
  15. package/dist/component/garmin/public.d.ts.map +1 -0
  16. package/dist/component/{garmin.js → garmin/public.js} +301 -215
  17. package/dist/component/garmin/public.js.map +1 -0
  18. package/dist/component/garmin/schemas/activity.d.ts +94 -0
  19. package/dist/component/garmin/schemas/activity.d.ts.map +1 -0
  20. package/dist/component/garmin/schemas/activity.js +27 -0
  21. package/dist/component/garmin/schemas/activity.js.map +1 -0
  22. package/dist/component/garmin/schemas/activityDetails.d.ts +146 -0
  23. package/dist/component/garmin/schemas/activityDetails.d.ts.map +1 -0
  24. package/dist/component/garmin/schemas/activityDetails.js +27 -0
  25. package/dist/component/garmin/schemas/activityDetails.js.map +1 -0
  26. package/dist/component/garmin/schemas/bloodPressure.d.ts +38 -0
  27. package/dist/component/garmin/schemas/bloodPressure.d.ts.map +1 -0
  28. package/dist/component/garmin/schemas/bloodPressure.js +27 -0
  29. package/dist/component/garmin/schemas/bloodPressure.js.map +1 -0
  30. package/dist/component/garmin/schemas/bodyCompositions.d.ts +42 -0
  31. package/dist/component/garmin/schemas/bodyCompositions.d.ts.map +1 -0
  32. package/dist/component/garmin/schemas/bodyCompositions.js +27 -0
  33. package/dist/component/garmin/schemas/bodyCompositions.js.map +1 -0
  34. package/dist/component/garmin/schemas/dailies.d.ts +98 -0
  35. package/dist/component/garmin/schemas/dailies.d.ts.map +1 -0
  36. package/dist/component/garmin/schemas/dailies.js +27 -0
  37. package/dist/component/garmin/schemas/dailies.js.map +1 -0
  38. package/dist/component/garmin/schemas/epochs.d.ts +54 -0
  39. package/dist/component/garmin/schemas/epochs.d.ts.map +1 -0
  40. package/dist/component/garmin/schemas/epochs.js +27 -0
  41. package/dist/component/garmin/schemas/epochs.js.map +1 -0
  42. package/dist/component/garmin/schemas/healthSnapshot.d.ts +48 -0
  43. package/dist/component/garmin/schemas/healthSnapshot.d.ts.map +1 -0
  44. package/dist/component/garmin/schemas/healthSnapshot.js +27 -0
  45. package/dist/component/garmin/schemas/healthSnapshot.js.map +1 -0
  46. package/dist/component/garmin/schemas/hrvSummary.d.ts +40 -0
  47. package/dist/component/garmin/schemas/hrvSummary.d.ts.map +1 -0
  48. package/dist/component/garmin/schemas/hrvSummary.js +27 -0
  49. package/dist/component/garmin/schemas/hrvSummary.js.map +1 -0
  50. package/dist/component/garmin/schemas/manuallyUpdatedActivities.d.ts +94 -0
  51. package/dist/component/garmin/schemas/manuallyUpdatedActivities.d.ts.map +1 -0
  52. package/dist/component/garmin/schemas/manuallyUpdatedActivities.js +27 -0
  53. package/dist/component/garmin/schemas/manuallyUpdatedActivities.js.map +1 -0
  54. package/dist/component/garmin/schemas/menstrualCycleTracking.d.ts +100 -0
  55. package/dist/component/garmin/schemas/menstrualCycleTracking.d.ts.map +1 -0
  56. package/dist/component/garmin/schemas/menstrualCycleTracking.js +28 -0
  57. package/dist/component/garmin/schemas/menstrualCycleTracking.js.map +1 -0
  58. package/dist/component/garmin/schemas/moveIQ.d.ts +40 -0
  59. package/dist/component/garmin/schemas/moveIQ.d.ts.map +1 -0
  60. package/dist/component/garmin/schemas/moveIQ.js +27 -0
  61. package/dist/component/garmin/schemas/moveIQ.js.map +1 -0
  62. package/dist/component/garmin/schemas/pulseOx.d.ts +38 -0
  63. package/dist/component/garmin/schemas/pulseOx.d.ts.map +1 -0
  64. package/dist/component/garmin/schemas/pulseOx.js +28 -0
  65. package/dist/component/garmin/schemas/pulseOx.js.map +1 -0
  66. package/dist/component/garmin/schemas/respiration.d.ts +34 -0
  67. package/dist/component/garmin/schemas/respiration.d.ts.map +1 -0
  68. package/dist/component/garmin/schemas/respiration.js +28 -0
  69. package/dist/component/garmin/schemas/respiration.js.map +1 -0
  70. package/dist/component/garmin/schemas/skinTemperature.d.ts +36 -0
  71. package/dist/component/garmin/schemas/skinTemperature.d.ts.map +1 -0
  72. package/dist/component/garmin/schemas/skinTemperature.js +28 -0
  73. package/dist/component/garmin/schemas/skinTemperature.js.map +1 -0
  74. package/dist/component/garmin/schemas/sleeps.d.ts +88 -0
  75. package/dist/component/garmin/schemas/sleeps.d.ts.map +1 -0
  76. package/dist/component/garmin/schemas/sleeps.js +27 -0
  77. package/dist/component/garmin/schemas/sleeps.js.map +1 -0
  78. package/dist/component/garmin/schemas/stress.d.ts +70 -0
  79. package/dist/component/garmin/schemas/stress.d.ts.map +1 -0
  80. package/dist/component/garmin/schemas/stress.js +28 -0
  81. package/dist/component/garmin/schemas/stress.js.map +1 -0
  82. package/dist/component/garmin/schemas/userMetrics.d.ts +36 -0
  83. package/dist/component/garmin/schemas/userMetrics.d.ts.map +1 -0
  84. package/dist/component/garmin/schemas/userMetrics.js +28 -0
  85. package/dist/component/garmin/schemas/userMetrics.js.map +1 -0
  86. package/dist/component/garmin/transform/activity.d.ts +13 -0
  87. package/dist/component/garmin/transform/activity.d.ts.map +1 -0
  88. package/dist/component/garmin/transform/activity.js +111 -0
  89. package/dist/component/garmin/transform/activity.js.map +1 -0
  90. package/dist/component/garmin/transform/activityDetails.d.ts +13 -0
  91. package/dist/component/garmin/transform/activityDetails.d.ts.map +1 -0
  92. package/dist/component/garmin/transform/activityDetails.js +173 -0
  93. package/dist/component/garmin/transform/activityDetails.js.map +1 -0
  94. package/dist/component/garmin/transform/bloodPressure.d.ts +12 -0
  95. package/dist/component/garmin/transform/bloodPressure.d.ts.map +1 -0
  96. package/dist/component/garmin/transform/bloodPressure.js +33 -0
  97. package/dist/component/garmin/transform/bloodPressure.js.map +1 -0
  98. package/dist/component/garmin/transform/bodyCompositions.d.ts +12 -0
  99. package/dist/component/garmin/transform/bodyCompositions.d.ts.map +1 -0
  100. package/dist/component/garmin/transform/bodyCompositions.js +42 -0
  101. package/dist/component/garmin/transform/bodyCompositions.js.map +1 -0
  102. package/dist/component/garmin/transform/dailies.d.ts +12 -0
  103. package/dist/component/garmin/transform/dailies.d.ts.map +1 -0
  104. package/dist/component/garmin/transform/dailies.js +132 -0
  105. package/dist/component/garmin/transform/dailies.js.map +1 -0
  106. package/dist/component/garmin/transform/epochs.d.ts +13 -0
  107. package/dist/component/garmin/transform/epochs.d.ts.map +1 -0
  108. package/dist/component/garmin/transform/epochs.js +76 -0
  109. package/dist/component/garmin/transform/epochs.js.map +1 -0
  110. package/dist/component/garmin/transform/healthSnapshot.d.ts +12 -0
  111. package/dist/component/garmin/transform/healthSnapshot.d.ts.map +1 -0
  112. package/dist/component/garmin/transform/healthSnapshot.js +111 -0
  113. package/dist/component/garmin/transform/healthSnapshot.js.map +1 -0
  114. package/dist/component/garmin/transform/hrvSummary.d.ts +12 -0
  115. package/dist/component/garmin/transform/hrvSummary.d.ts.map +1 -0
  116. package/dist/component/garmin/transform/hrvSummary.js +45 -0
  117. package/dist/component/garmin/transform/hrvSummary.js.map +1 -0
  118. package/dist/component/garmin/transform/manuallyUpdatedActivities.d.ts +11 -0
  119. package/dist/component/garmin/transform/manuallyUpdatedActivities.d.ts.map +1 -0
  120. package/dist/component/garmin/transform/manuallyUpdatedActivities.js +20 -0
  121. package/dist/component/garmin/transform/manuallyUpdatedActivities.js.map +1 -0
  122. package/dist/component/garmin/transform/menstrualCycleTracking.d.ts +10 -0
  123. package/dist/component/garmin/transform/menstrualCycleTracking.d.ts.map +1 -0
  124. package/dist/component/garmin/transform/menstrualCycleTracking.js +43 -0
  125. package/dist/component/garmin/transform/menstrualCycleTracking.js.map +1 -0
  126. package/dist/component/garmin/transform/moveIQ.d.ts +17 -0
  127. package/dist/component/garmin/transform/moveIQ.d.ts.map +1 -0
  128. package/dist/component/garmin/transform/moveIQ.js +41 -0
  129. package/dist/component/garmin/transform/moveIQ.js.map +1 -0
  130. package/dist/component/garmin/transform/pulseOx.d.ts +12 -0
  131. package/dist/component/garmin/transform/pulseOx.d.ts.map +1 -0
  132. package/dist/component/garmin/transform/pulseOx.js +46 -0
  133. package/dist/component/garmin/transform/pulseOx.js.map +1 -0
  134. package/dist/component/garmin/transform/respiration.d.ts +12 -0
  135. package/dist/component/garmin/transform/respiration.d.ts.map +1 -0
  136. package/dist/component/garmin/transform/respiration.js +54 -0
  137. package/dist/component/garmin/transform/respiration.js.map +1 -0
  138. package/dist/component/garmin/transform/skinTemperature.d.ts +12 -0
  139. package/dist/component/garmin/transform/skinTemperature.d.ts.map +1 -0
  140. package/dist/component/garmin/transform/skinTemperature.js +38 -0
  141. package/dist/component/garmin/transform/skinTemperature.js.map +1 -0
  142. package/dist/component/garmin/transform/sleeps.d.ts +55 -0
  143. package/dist/component/garmin/transform/sleeps.d.ts.map +1 -0
  144. package/dist/component/garmin/transform/sleeps.js +120 -0
  145. package/dist/component/garmin/transform/sleeps.js.map +1 -0
  146. package/dist/component/garmin/transform/stress.d.ts +12 -0
  147. package/dist/component/garmin/transform/stress.d.ts.map +1 -0
  148. package/dist/component/garmin/transform/stress.js +56 -0
  149. package/dist/component/garmin/transform/stress.js.map +1 -0
  150. package/dist/component/garmin/transform/userMetrics.d.ts +12 -0
  151. package/dist/component/garmin/transform/userMetrics.d.ts.map +1 -0
  152. package/dist/component/garmin/transform/userMetrics.js +48 -0
  153. package/dist/component/garmin/transform/userMetrics.js.map +1 -0
  154. package/dist/component/garmin/types/garmin.d.ts +21 -0
  155. package/dist/component/garmin/types/garmin.d.ts.map +1 -0
  156. package/dist/component/garmin/types/garmin.js +6 -0
  157. package/dist/component/garmin/types/garmin.js.map +1 -0
  158. package/dist/component/garmin/types/zod/zod.gen.d.ts +1319 -0
  159. package/dist/component/garmin/types/zod/zod.gen.d.ts.map +1 -0
  160. package/dist/component/garmin/types/zod/zod.gen.js +784 -0
  161. package/dist/component/garmin/types/zod/zod.gen.js.map +1 -0
  162. package/dist/component/garmin/webhooks.d.ts +141 -0
  163. package/dist/component/garmin/webhooks.d.ts.map +1 -0
  164. package/dist/component/garmin/webhooks.js +766 -0
  165. package/dist/component/garmin/webhooks.js.map +1 -0
  166. package/dist/component/private.d.ts +20 -2
  167. package/dist/component/private.d.ts.map +1 -1
  168. package/dist/component/private.js +18 -0
  169. package/dist/component/private.js.map +1 -1
  170. package/dist/component/public.d.ts +433 -387
  171. package/dist/component/public.d.ts.map +1 -1
  172. package/dist/component/public.js +12 -2
  173. package/dist/component/public.js.map +1 -1
  174. package/dist/component/schema.d.ts +217 -162
  175. package/dist/component/schema.d.ts.map +1 -1
  176. package/dist/component/schema.js +2 -1
  177. package/dist/component/schema.js.map +1 -1
  178. package/dist/component/strava/private.d.ts +30 -0
  179. package/dist/component/strava/private.d.ts.map +1 -0
  180. package/dist/component/strava/private.js +71 -0
  181. package/dist/component/strava/private.js.map +1 -0
  182. package/dist/component/{strava.d.ts → strava/public.d.ts} +3 -31
  183. package/dist/component/strava/public.d.ts.map +1 -0
  184. package/dist/component/{strava.js → strava/public.js} +22 -101
  185. package/dist/component/strava/public.js.map +1 -0
  186. package/dist/component/validators/activity.d.ts +6 -0
  187. package/dist/component/validators/activity.d.ts.map +1 -1
  188. package/dist/component/validators/activity.js.map +1 -1
  189. package/dist/component/validators/body.d.ts +20 -14
  190. package/dist/component/validators/body.d.ts.map +1 -1
  191. package/dist/component/validators/body.js.map +1 -1
  192. package/dist/component/validators/connection.d.ts +1 -0
  193. package/dist/component/validators/connection.d.ts.map +1 -1
  194. package/dist/component/validators/connection.js +2 -0
  195. package/dist/component/validators/connection.js.map +1 -1
  196. package/dist/component/validators/daily.d.ts +46 -5
  197. package/dist/component/validators/daily.d.ts.map +1 -1
  198. package/dist/component/validators/daily.js +10 -1
  199. package/dist/component/validators/daily.js.map +1 -1
  200. package/dist/component/validators/enums.d.ts +2 -2
  201. package/dist/component/validators/menstruation.d.ts +5 -0
  202. package/dist/component/validators/menstruation.d.ts.map +1 -1
  203. package/dist/component/validators/menstruation.js.map +1 -1
  204. package/dist/component/validators/plannedWorkout.d.ts +5 -1
  205. package/dist/component/validators/plannedWorkout.d.ts.map +1 -1
  206. package/dist/component/validators/plannedWorkout.js +4 -0
  207. package/dist/component/validators/plannedWorkout.js.map +1 -1
  208. package/dist/component/validators/sleep.d.ts +8 -8
  209. package/dist/garmin/bloodPressure.d.ts +28 -0
  210. package/dist/garmin/bloodPressure.d.ts.map +1 -0
  211. package/dist/garmin/bloodPressure.js +34 -0
  212. package/dist/garmin/bloodPressure.js.map +1 -0
  213. package/dist/garmin/body.js +1 -1
  214. package/dist/garmin/body.js.map +1 -1
  215. package/dist/garmin/client.d.ts +117 -17
  216. package/dist/garmin/client.d.ts.map +1 -1
  217. package/dist/garmin/client.js +337 -43
  218. package/dist/garmin/client.js.map +1 -1
  219. package/dist/garmin/daily.d.ts.map +1 -1
  220. package/dist/garmin/daily.js +3 -3
  221. package/dist/garmin/daily.js.map +1 -1
  222. package/dist/garmin/hrv.d.ts +30 -0
  223. package/dist/garmin/hrv.d.ts.map +1 -0
  224. package/dist/garmin/hrv.js +45 -0
  225. package/dist/garmin/hrv.js.map +1 -0
  226. package/dist/garmin/index.d.ts +16 -4
  227. package/dist/garmin/index.d.ts.map +1 -1
  228. package/dist/garmin/index.js +8 -2
  229. package/dist/garmin/index.js.map +1 -1
  230. package/dist/garmin/maps/activity-type.d.ts +1 -2
  231. package/dist/garmin/maps/activity-type.d.ts.map +1 -1
  232. package/dist/garmin/maps/activity-type.js +1 -0
  233. package/dist/garmin/maps/activity-type.js.map +1 -1
  234. package/dist/garmin/menstruation.d.ts +6 -4
  235. package/dist/garmin/menstruation.d.ts.map +1 -1
  236. package/dist/garmin/menstruation.js +12 -8
  237. package/dist/garmin/menstruation.js.map +1 -1
  238. package/dist/garmin/pulseOx.d.ts +24 -0
  239. package/dist/garmin/pulseOx.d.ts.map +1 -0
  240. package/dist/garmin/pulseOx.js +33 -0
  241. package/dist/garmin/pulseOx.js.map +1 -0
  242. package/dist/garmin/respiration.d.ts +29 -0
  243. package/dist/garmin/respiration.d.ts.map +1 -0
  244. package/dist/garmin/respiration.js +42 -0
  245. package/dist/garmin/respiration.js.map +1 -0
  246. package/dist/garmin/skinTemp.d.ts +27 -0
  247. package/dist/garmin/skinTemp.d.ts.map +1 -0
  248. package/dist/garmin/skinTemp.js +35 -0
  249. package/dist/garmin/skinTemp.js.map +1 -0
  250. package/dist/garmin/sleep.d.ts +4 -4
  251. package/dist/garmin/sleep.d.ts.map +1 -1
  252. package/dist/garmin/sleep.js +15 -9
  253. package/dist/garmin/sleep.js.map +1 -1
  254. package/dist/garmin/stressDetails.d.ts +30 -0
  255. package/dist/garmin/stressDetails.d.ts.map +1 -0
  256. package/dist/garmin/stressDetails.js +49 -0
  257. package/dist/garmin/stressDetails.js.map +1 -0
  258. package/dist/garmin/sync.d.ts +14 -0
  259. package/dist/garmin/sync.d.ts.map +1 -1
  260. package/dist/garmin/sync.js +290 -7
  261. package/dist/garmin/sync.js.map +1 -1
  262. package/dist/garmin/types.d.ts +77 -186
  263. package/dist/garmin/types.d.ts.map +1 -1
  264. package/dist/garmin/types.js +4 -2
  265. package/dist/garmin/types.js.map +1 -1
  266. package/dist/garmin/userMetrics.d.ts +23 -0
  267. package/dist/garmin/userMetrics.d.ts.map +1 -0
  268. package/dist/garmin/userMetrics.js +41 -0
  269. package/dist/garmin/userMetrics.js.map +1 -0
  270. package/dist/validators.d.ts +138 -56
  271. package/dist/validators.d.ts.map +1 -1
  272. package/dist/validators.js +2 -2
  273. package/dist/validators.js.map +1 -1
  274. package/package.json +130 -124
  275. package/src/client/index.ts +86 -18
  276. package/src/component/_generated/api.ts +96 -4
  277. package/src/component/_generated/component.ts +271 -144
  278. package/src/{garmin → component/garmin}/auth.ts +8 -1
  279. package/src/component/garmin/client.ts +39 -0
  280. package/src/component/garmin/private.ts +1798 -0
  281. package/src/component/garmin/public.ts +938 -0
  282. package/src/component/garmin/schemas/activity.ts +40 -0
  283. package/src/component/garmin/schemas/activityDetails.ts +45 -0
  284. package/src/component/garmin/schemas/bloodPressure.ts +38 -0
  285. package/src/component/garmin/schemas/bodyCompositions.ts +38 -0
  286. package/src/component/garmin/schemas/dailies.ts +38 -0
  287. package/src/component/garmin/schemas/epochs.ts +38 -0
  288. package/src/component/garmin/schemas/healthSnapshot.ts +38 -0
  289. package/src/component/garmin/schemas/hrvSummary.ts +38 -0
  290. package/src/component/garmin/schemas/manuallyUpdatedActivities.ts +49 -0
  291. package/src/component/garmin/schemas/menstrualCycleTracking.ts +39 -0
  292. package/src/component/garmin/schemas/moveIQ.ts +38 -0
  293. package/src/component/garmin/schemas/pulseOx.ts +39 -0
  294. package/src/component/garmin/schemas/respiration.ts +39 -0
  295. package/src/component/garmin/schemas/skinTemperature.ts +39 -0
  296. package/src/component/garmin/schemas/sleeps.ts +38 -0
  297. package/src/component/garmin/schemas/stress.ts +43 -0
  298. package/src/component/garmin/schemas/userMetrics.ts +39 -0
  299. package/src/component/garmin/transform/activity.ts +143 -0
  300. package/src/component/garmin/transform/activityDetails.ts +236 -0
  301. package/src/component/garmin/transform/bloodPressure.ts +39 -0
  302. package/src/component/garmin/transform/bodyCompositions.ts +51 -0
  303. package/src/component/garmin/transform/dailies.ts +179 -0
  304. package/src/component/garmin/transform/epochs.ts +94 -0
  305. package/src/component/garmin/transform/healthSnapshot.ts +152 -0
  306. package/src/component/garmin/transform/hrvSummary.ts +56 -0
  307. package/src/component/garmin/transform/manuallyUpdatedActivities.ts +27 -0
  308. package/src/{garmin/maps/activity-type.ts → component/garmin/transform/maps/activityType.ts} +116 -116
  309. package/src/{garmin/maps/sleep-level.ts → component/garmin/transform/maps/sleepLevel.ts} +22 -22
  310. package/src/component/garmin/transform/menstrualCycleTracking.ts +48 -0
  311. package/src/component/garmin/transform/moveIQ.ts +48 -0
  312. package/src/{garmin → component/garmin/transform}/plannedWorkout.ts +328 -333
  313. package/src/component/garmin/transform/pulseOx.ts +64 -0
  314. package/src/component/garmin/transform/respiration.ts +73 -0
  315. package/src/component/garmin/transform/skinTemperature.ts +44 -0
  316. package/src/component/garmin/transform/sleeps.ts +159 -0
  317. package/src/component/garmin/transform/stress.ts +78 -0
  318. package/src/component/garmin/transform/userMetrics.ts +56 -0
  319. package/src/component/garmin/types/specs/training-api-workouts.json +699 -0
  320. package/src/component/garmin/types/specs/wellness-api.json +1 -0
  321. package/src/component/garmin/types/trainingApiWorkouts/client/client.gen.ts +290 -0
  322. package/src/component/garmin/types/trainingApiWorkouts/client/index.ts +25 -0
  323. package/src/component/garmin/types/trainingApiWorkouts/client/types.gen.ts +214 -0
  324. package/src/component/garmin/types/trainingApiWorkouts/client/utils.gen.ts +316 -0
  325. package/src/component/garmin/types/trainingApiWorkouts/client.gen.ts +16 -0
  326. package/src/component/garmin/types/trainingApiWorkouts/core/auth.gen.ts +41 -0
  327. package/src/component/garmin/types/trainingApiWorkouts/core/bodySerializer.gen.ts +82 -0
  328. package/src/component/garmin/types/trainingApiWorkouts/core/params.gen.ts +169 -0
  329. package/src/component/garmin/types/trainingApiWorkouts/core/pathSerializer.gen.ts +171 -0
  330. package/src/component/garmin/types/trainingApiWorkouts/core/queryKeySerializer.gen.ts +117 -0
  331. package/src/component/garmin/types/trainingApiWorkouts/core/serverSentEvents.gen.ts +243 -0
  332. package/src/component/garmin/types/trainingApiWorkouts/core/types.gen.ts +104 -0
  333. package/src/component/garmin/types/trainingApiWorkouts/core/utils.gen.ts +140 -0
  334. package/src/component/garmin/types/trainingApiWorkouts/index.ts +4 -0
  335. package/src/component/garmin/types/trainingApiWorkouts/sdk.gen.ts +126 -0
  336. package/src/component/garmin/types/trainingApiWorkouts/types.gen.ts +387 -0
  337. package/src/component/garmin/types/trainingApiWorkouts/zod.gen.ts +423 -0
  338. package/src/component/garmin/types/wellnessApi/client/client.gen.ts +290 -0
  339. package/src/component/garmin/types/wellnessApi/client/index.ts +25 -0
  340. package/src/component/garmin/types/wellnessApi/client/types.gen.ts +214 -0
  341. package/src/component/garmin/types/wellnessApi/client/utils.gen.ts +316 -0
  342. package/src/component/garmin/types/wellnessApi/client.gen.ts +16 -0
  343. package/src/component/garmin/types/wellnessApi/core/auth.gen.ts +41 -0
  344. package/src/component/garmin/types/wellnessApi/core/bodySerializer.gen.ts +82 -0
  345. package/src/component/garmin/types/wellnessApi/core/params.gen.ts +169 -0
  346. package/src/component/garmin/types/wellnessApi/core/pathSerializer.gen.ts +171 -0
  347. package/src/component/garmin/types/wellnessApi/core/queryKeySerializer.gen.ts +117 -0
  348. package/src/component/garmin/types/wellnessApi/core/serverSentEvents.gen.ts +243 -0
  349. package/src/component/garmin/types/wellnessApi/core/types.gen.ts +104 -0
  350. package/src/component/garmin/types/wellnessApi/core/utils.gen.ts +140 -0
  351. package/src/component/garmin/types/wellnessApi/index.ts +4 -0
  352. package/src/component/garmin/types/wellnessApi/sdk.gen.ts +207 -0
  353. package/src/component/garmin/types/wellnessApi/types.gen.ts +2942 -0
  354. package/src/component/garmin/types/wellnessApi/zod.gen.ts +878 -0
  355. package/src/component/garmin/utils.ts +25 -0
  356. package/src/component/garmin/webhooks.ts +852 -0
  357. package/src/component/private.ts +21 -0
  358. package/src/component/public.ts +11 -2
  359. package/src/component/schema.ts +2 -1
  360. package/src/component/strava/private.ts +89 -0
  361. package/src/component/{strava.ts → strava/public.ts} +341 -404
  362. package/src/component/validators/activity.ts +5 -0
  363. package/src/component/validators/body.ts +5 -0
  364. package/src/component/validators/connection.ts +2 -0
  365. package/src/component/validators/daily.ts +20 -0
  366. package/src/component/validators/menstruation.ts +5 -1
  367. package/src/component/validators/plannedWorkout.ts +9 -0
  368. package/src/validators.ts +12 -2
  369. package/dist/component/garmin.d.ts.map +0 -1
  370. package/dist/component/garmin.js.map +0 -1
  371. package/dist/component/strava.d.ts.map +0 -1
  372. package/dist/component/strava.js.map +0 -1
  373. package/dist/garmin/activity.d.ts +0 -101
  374. package/dist/garmin/activity.d.ts.map +0 -1
  375. package/dist/garmin/activity.js +0 -207
  376. package/dist/garmin/activity.js.map +0 -1
  377. package/src/component/garmin.ts +0 -850
  378. package/src/garmin/activity.test.ts +0 -178
  379. package/src/garmin/activity.ts +0 -272
  380. package/src/garmin/auth.test.ts +0 -103
  381. package/src/garmin/body.ts +0 -59
  382. package/src/garmin/client.ts +0 -407
  383. package/src/garmin/daily.ts +0 -211
  384. package/src/garmin/index.ts +0 -75
  385. package/src/garmin/maps/activity-type.test.ts +0 -78
  386. package/src/garmin/menstruation.ts +0 -42
  387. package/src/garmin/sleep.test.ts +0 -110
  388. package/src/garmin/sleep.ts +0 -170
  389. package/src/garmin/sync.ts +0 -223
  390. package/src/garmin/types.ts +0 -480
@@ -1,850 +0,0 @@
1
- // ─── Garmin Component Actions ────────────────────────────────────────────────
2
- // Public actions that handle the full Garmin OAuth 2.0 PKCE + sync lifecycle.
3
- // The host app calls these through the Soma class, which threads the
4
- // credentials automatically from env vars or constructor config.
5
- //
6
- // Internal mutations manage the providerTokens table (token CRUD).
7
-
8
- import { v } from "convex/values";
9
- import { anyApi } from "convex/server";
10
- import {
11
- action,
12
- internalMutation,
13
- internalQuery,
14
- } from "./_generated/server.js";
15
- import {
16
- generateCodeVerifier,
17
- generateCodeChallenge,
18
- generateState,
19
- buildAuthUrl,
20
- exchangeCode,
21
- refreshToken,
22
- } from "../garmin/auth.js";
23
- import { GarminClient } from "../garmin/client.js";
24
- import { transformActivity } from "../garmin/activity.js";
25
- import { transformDaily } from "../garmin/daily.js";
26
- import { transformSleep } from "../garmin/sleep.js";
27
- import { transformBody } from "../garmin/body.js";
28
- import { transformMenstruation } from "../garmin/menstruation.js";
29
- import { transformPlannedWorkoutToGarmin } from "../garmin/plannedWorkout.js";
30
-
31
- // Use anyApi to avoid circular type references between this file and _generated/api.ts.
32
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
33
- const publicApi: any = anyApi;
34
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
35
- const internalApi: any = anyApi;
36
-
37
- // Default sync window: last 30 days
38
- const DEFAULT_SYNC_DAYS = 30;
39
-
40
- // Refresh buffer: refresh tokens 10 minutes before expiry
41
- const REFRESH_BUFFER_SECONDS = 600;
42
-
43
- // ─── Internal Pending OAuth CRUD ─────────────────────────────────────────────
44
- // Temporary storage for in-progress Garmin OAuth 2.0 PKCE flows.
45
- // Bridges getGarminAuthUrl and completeGarminOAuth.
46
-
47
- export const storePendingOAuth = internalMutation({
48
- args: {
49
- provider: v.string(),
50
- state: v.string(),
51
- codeVerifier: v.string(),
52
- userId: v.string(),
53
- },
54
- returns: v.null(),
55
- handler: async (ctx, args) => {
56
- await ctx.db.insert("pendingOAuth", {
57
- ...args,
58
- createdAt: Date.now(),
59
- });
60
- return null;
61
- },
62
- });
63
-
64
- export const getPendingOAuth = internalQuery({
65
- args: { state: v.string() },
66
- returns: v.union(
67
- v.object({
68
- _id: v.id("pendingOAuth"),
69
- _creationTime: v.number(),
70
- provider: v.string(),
71
- state: v.string(),
72
- codeVerifier: v.string(),
73
- userId: v.string(),
74
- createdAt: v.number(),
75
- }),
76
- v.null(),
77
- ),
78
- handler: async (ctx, args) => {
79
- return await ctx.db
80
- .query("pendingOAuth")
81
- .withIndex("by_state", (q) => q.eq("state", args.state))
82
- .first();
83
- },
84
- });
85
-
86
- export const deletePendingOAuth = internalMutation({
87
- args: { state: v.string() },
88
- returns: v.null(),
89
- handler: async (ctx, args) => {
90
- const pending = await ctx.db
91
- .query("pendingOAuth")
92
- .withIndex("by_state", (q) => q.eq("state", args.state))
93
- .first();
94
- if (pending) {
95
- await ctx.db.delete(pending._id);
96
- }
97
- return null;
98
- },
99
- });
100
-
101
- // ─── Internal Token CRUD ─────────────────────────────────────────────────────
102
-
103
- /**
104
- * Store OAuth 2.0 tokens for a Garmin connection.
105
- * Upserts by connectionId — one token record per connection.
106
- */
107
- export const storeTokens = internalMutation({
108
- args: {
109
- connectionId: v.id("connections"),
110
- accessToken: v.string(),
111
- refreshToken: v.string(),
112
- expiresAt: v.number(),
113
- },
114
- returns: v.null(),
115
- handler: async (ctx, args) => {
116
- const existing = await ctx.db
117
- .query("providerTokens")
118
- .withIndex("by_connectionId", (q) =>
119
- q.eq("connectionId", args.connectionId),
120
- )
121
- .first();
122
-
123
- if (existing) {
124
- await ctx.db.patch(existing._id, {
125
- accessToken: args.accessToken,
126
- refreshToken: args.refreshToken,
127
- expiresAt: args.expiresAt,
128
- });
129
- return null;
130
- }
131
-
132
- await ctx.db.insert("providerTokens", {
133
- connectionId: args.connectionId,
134
- accessToken: args.accessToken,
135
- refreshToken: args.refreshToken,
136
- expiresAt: args.expiresAt,
137
- });
138
- return null;
139
- },
140
- });
141
-
142
- /**
143
- * Get stored tokens for a connection.
144
- */
145
- export const getTokens = internalQuery({
146
- args: { connectionId: v.id("connections") },
147
- returns: v.union(
148
- v.object({
149
- _id: v.id("providerTokens"),
150
- _creationTime: v.number(),
151
- connectionId: v.id("connections"),
152
- accessToken: v.string(),
153
- refreshToken: v.optional(v.string()),
154
- expiresAt: v.optional(v.number()),
155
- }),
156
- v.null(),
157
- ),
158
- handler: async (ctx, args) => {
159
- return await ctx.db
160
- .query("providerTokens")
161
- .withIndex("by_connectionId", (q) =>
162
- q.eq("connectionId", args.connectionId),
163
- )
164
- .first();
165
- },
166
- });
167
-
168
- /**
169
- * Delete stored tokens for a connection.
170
- */
171
- export const deleteTokens = internalMutation({
172
- args: { connectionId: v.id("connections") },
173
- returns: v.null(),
174
- handler: async (ctx, args) => {
175
- const existing = await ctx.db
176
- .query("providerTokens")
177
- .withIndex("by_connectionId", (q) =>
178
- q.eq("connectionId", args.connectionId),
179
- )
180
- .first();
181
-
182
- if (existing) {
183
- await ctx.db.delete(existing._id);
184
- }
185
- return null;
186
- },
187
- });
188
-
189
- // ─── Public Actions ──────────────────────────────────────────────────────────
190
-
191
- /**
192
- * Generate a Garmin OAuth 2.0 authorization URL with PKCE.
193
- *
194
- * If `userId` is provided, the PKCE code verifier and state are stored in the
195
- * component's `pendingOAuth` table so that `completeGarminOAuth` can look
196
- * them up automatically when the callback fires. This is the recommended
197
- * flow when using `registerRoutes`.
198
- *
199
- * If `userId` is omitted, the host app must store the returned `codeVerifier`
200
- * itself and pass it to `connectGarmin` manually.
201
- */
202
- export const getGarminAuthUrl = action({
203
- args: {
204
- clientId: v.string(),
205
- redirectUri: v.optional(v.string()),
206
- userId: v.optional(v.string()),
207
- },
208
- returns: v.object({
209
- authUrl: v.string(),
210
- state: v.string(),
211
- codeVerifier: v.string(),
212
- }),
213
- handler: async (ctx, args) => {
214
- const codeVerifier = generateCodeVerifier();
215
- const codeChallenge = await generateCodeChallenge(codeVerifier);
216
- const state = generateState();
217
-
218
- const authUrl = buildAuthUrl({
219
- clientId: args.clientId,
220
- codeChallenge,
221
- redirectUri: args.redirectUri,
222
- state,
223
- });
224
-
225
- if (args.userId) {
226
- await ctx.runMutation(internalApi.garmin.storePendingOAuth, {
227
- provider: "GARMIN",
228
- state,
229
- codeVerifier,
230
- userId: args.userId,
231
- });
232
- }
233
-
234
- return { authUrl, state, codeVerifier };
235
- },
236
- });
237
-
238
- /**
239
- * Exchange an authorization code for tokens + initial sync.
240
- *
241
- * Used in the manual flow where the host app stores the code verifier
242
- * and handles the callback itself.
243
- */
244
- export const connectGarmin = action({
245
- args: {
246
- userId: v.string(),
247
- clientId: v.string(),
248
- clientSecret: v.string(),
249
- code: v.string(),
250
- codeVerifier: v.string(),
251
- redirectUri: v.optional(v.string()),
252
- },
253
- returns: v.object({
254
- connectionId: v.string(),
255
- synced: v.object({
256
- activities: v.number(),
257
- dailies: v.number(),
258
- sleep: v.number(),
259
- body: v.number(),
260
- menstruation: v.number(),
261
- }),
262
- errors: v.array(
263
- v.object({ type: v.string(), id: v.string(), error: v.string() }),
264
- ),
265
- }),
266
- handler: async (ctx, args) => {
267
- const tokenResult = await exchangeCode({
268
- clientId: args.clientId,
269
- clientSecret: args.clientSecret,
270
- code: args.code,
271
- codeVerifier: args.codeVerifier,
272
- redirectUri: args.redirectUri,
273
- });
274
-
275
- const connectionId = await ctx.runMutation(publicApi.public.connect, {
276
- userId: args.userId,
277
- provider: "GARMIN",
278
- });
279
-
280
- const expiresAt = Math.floor(Date.now() / 1000) + tokenResult.expires_in;
281
- await ctx.runMutation(internalApi.garmin.storeTokens, {
282
- connectionId,
283
- accessToken: tokenResult.access_token,
284
- refreshToken: tokenResult.refresh_token,
285
- expiresAt,
286
- });
287
-
288
- const client = new GarminClient({
289
- accessToken: tokenResult.access_token,
290
- });
291
-
292
- const now = Math.floor(Date.now() / 1000);
293
- const thirtyDaysAgo = now - DEFAULT_SYNC_DAYS * 86400;
294
- const timeRange = {
295
- uploadStartTimeInSeconds: thirtyDaysAgo,
296
- uploadEndTimeInSeconds: now,
297
- };
298
-
299
- const result = await syncAllTypes(ctx, client, {
300
- connectionId,
301
- userId: args.userId,
302
- timeRange,
303
- });
304
-
305
- await ctx.runMutation(publicApi.public.updateConnection, {
306
- connectionId,
307
- lastDataUpdate: new Date().toISOString(),
308
- });
309
-
310
- return {
311
- connectionId,
312
- synced: result.synced,
313
- errors: result.errors,
314
- };
315
- },
316
- });
317
-
318
- /**
319
- * Complete a Garmin OAuth 2.0 flow using stored pending state.
320
- *
321
- * Used by `registerRoutes` — the callback handler calls this with the
322
- * `code` and `state` from the redirect. The action looks up the pending
323
- * state (codeVerifier, userId) stored during `getGarminAuthUrl`,
324
- * exchanges for tokens, creates the connection, syncs data, and
325
- * cleans up the pending entry.
326
- */
327
- export const completeGarminOAuth = action({
328
- args: {
329
- code: v.string(),
330
- state: v.string(),
331
- clientId: v.string(),
332
- clientSecret: v.string(),
333
- redirectUri: v.optional(v.string()),
334
- },
335
- returns: v.object({
336
- connectionId: v.string(),
337
- synced: v.object({
338
- activities: v.number(),
339
- dailies: v.number(),
340
- sleep: v.number(),
341
- body: v.number(),
342
- menstruation: v.number(),
343
- }),
344
- errors: v.array(
345
- v.object({ type: v.string(), id: v.string(), error: v.string() }),
346
- ),
347
- }),
348
- handler: async (ctx, args) => {
349
- const pending = await ctx.runQuery(internalApi.garmin.getPendingOAuth, {
350
- state: args.state,
351
- });
352
- if (!pending) {
353
- throw new Error(
354
- "No pending Garmin OAuth state found for this state parameter. " +
355
- "The authorization may have expired or was already used.",
356
- );
357
- }
358
-
359
- const tokenResult = await exchangeCode({
360
- clientId: args.clientId,
361
- clientSecret: args.clientSecret,
362
- code: args.code,
363
- codeVerifier: pending.codeVerifier,
364
- redirectUri: args.redirectUri,
365
- });
366
-
367
- await ctx.runMutation(internalApi.garmin.deletePendingOAuth, {
368
- state: args.state,
369
- });
370
-
371
- const connectionId = await ctx.runMutation(publicApi.public.connect, {
372
- userId: pending.userId,
373
- provider: "GARMIN",
374
- });
375
-
376
- const expiresAt = Math.floor(Date.now() / 1000) + tokenResult.expires_in;
377
- await ctx.runMutation(internalApi.garmin.storeTokens, {
378
- connectionId,
379
- accessToken: tokenResult.access_token,
380
- refreshToken: tokenResult.refresh_token,
381
- expiresAt,
382
- });
383
-
384
- const client = new GarminClient({
385
- accessToken: tokenResult.access_token,
386
- });
387
-
388
- const now = Math.floor(Date.now() / 1000);
389
- const thirtyDaysAgo = now - DEFAULT_SYNC_DAYS * 86400;
390
- const timeRange = {
391
- uploadStartTimeInSeconds: thirtyDaysAgo,
392
- uploadEndTimeInSeconds: now,
393
- };
394
-
395
- const result = await syncAllTypes(ctx, client, {
396
- connectionId,
397
- userId: pending.userId,
398
- timeRange,
399
- });
400
-
401
- await ctx.runMutation(publicApi.public.updateConnection, {
402
- connectionId,
403
- lastDataUpdate: new Date().toISOString(),
404
- });
405
-
406
- return {
407
- connectionId,
408
- synced: result.synced,
409
- errors: result.errors,
410
- };
411
- },
412
- });
413
-
414
- /**
415
- * Incremental Garmin sync for an already-connected user.
416
- *
417
- * Looks up the stored tokens, refreshes if expired, and syncs all data
418
- * types for the specified time range (defaults to last 30 days).
419
- */
420
- export const syncGarmin = action({
421
- args: {
422
- userId: v.string(),
423
- clientId: v.string(),
424
- clientSecret: v.string(),
425
- startTimeInSeconds: v.optional(v.number()),
426
- endTimeInSeconds: v.optional(v.number()),
427
- },
428
- returns: v.object({
429
- synced: v.object({
430
- activities: v.number(),
431
- dailies: v.number(),
432
- sleep: v.number(),
433
- body: v.number(),
434
- menstruation: v.number(),
435
- }),
436
- errors: v.array(
437
- v.object({ type: v.string(), id: v.string(), error: v.string() }),
438
- ),
439
- }),
440
- handler: async (ctx, args) => {
441
- const connection = await ctx.runQuery(
442
- internalApi.private.getConnectionByProvider,
443
- { userId: args.userId, provider: "GARMIN" },
444
- );
445
- if (!connection) {
446
- throw new Error(
447
- `No Garmin connection found for user "${args.userId}". ` +
448
- "Call connectGarmin first.",
449
- );
450
- }
451
- if (!connection.active) {
452
- throw new Error(
453
- `Garmin connection for user "${args.userId}" is inactive. Reconnect first.`,
454
- );
455
- }
456
-
457
- const connectionId = connection._id;
458
-
459
- const tokenDoc = await ctx.runQuery(internalApi.garmin.getTokens, {
460
- connectionId,
461
- });
462
- if (!tokenDoc) {
463
- throw new Error(
464
- "No Garmin tokens found for this connection. " +
465
- "The connection may have been created before token storage was available.",
466
- );
467
- }
468
-
469
- let accessToken = tokenDoc.accessToken;
470
-
471
- // Refresh the token if it's expired or about to expire
472
- const nowSeconds = Math.floor(Date.now() / 1000);
473
- if (
474
- tokenDoc.expiresAt &&
475
- tokenDoc.refreshToken &&
476
- nowSeconds >= tokenDoc.expiresAt - REFRESH_BUFFER_SECONDS
477
- ) {
478
- const refreshed = await refreshToken({
479
- clientId: args.clientId,
480
- clientSecret: args.clientSecret,
481
- refreshToken: tokenDoc.refreshToken,
482
- });
483
-
484
- accessToken = refreshed.access_token;
485
- const newExpiresAt = nowSeconds + refreshed.expires_in;
486
- await ctx.runMutation(internalApi.garmin.storeTokens, {
487
- connectionId,
488
- accessToken: refreshed.access_token,
489
- refreshToken: refreshed.refresh_token,
490
- expiresAt: newExpiresAt,
491
- });
492
- }
493
-
494
- const client = new GarminClient({ accessToken });
495
-
496
- const now = Math.floor(Date.now() / 1000);
497
- const timeRange = {
498
- uploadStartTimeInSeconds:
499
- args.startTimeInSeconds ?? now - DEFAULT_SYNC_DAYS * 86400,
500
- uploadEndTimeInSeconds: args.endTimeInSeconds ?? now,
501
- };
502
-
503
- const result = await syncAllTypes(ctx, client, {
504
- connectionId,
505
- userId: args.userId,
506
- timeRange,
507
- });
508
-
509
- await ctx.runMutation(publicApi.public.updateConnection, {
510
- connectionId,
511
- lastDataUpdate: new Date().toISOString(),
512
- });
513
-
514
- return result;
515
- },
516
- });
517
-
518
- /**
519
- * Disconnect a user from Garmin.
520
- *
521
- * Deregisters the user via the Garmin API (best-effort), deletes stored
522
- * tokens, and sets the connection to inactive.
523
- */
524
- export const disconnectGarmin = action({
525
- args: {
526
- userId: v.string(),
527
- },
528
- returns: v.null(),
529
- handler: async (ctx, args) => {
530
- const connection = await ctx.runQuery(
531
- internalApi.private.getConnectionByProvider,
532
- { userId: args.userId, provider: "GARMIN" },
533
- );
534
- if (!connection) {
535
- throw new Error(
536
- `No Garmin connection found for user "${args.userId}".`,
537
- );
538
- }
539
-
540
- const connectionId = connection._id;
541
-
542
- // Best-effort: deregister user at Garmin
543
- const tokenDoc = await ctx.runQuery(internalApi.garmin.getTokens, {
544
- connectionId,
545
- });
546
- if (tokenDoc) {
547
- try {
548
- const client = new GarminClient({ accessToken: tokenDoc.accessToken });
549
- await client.deleteUserRegistration();
550
- } catch {
551
- // Deregistration is best-effort; proceed with local cleanup
552
- }
553
- }
554
-
555
- await ctx.runMutation(internalApi.garmin.deleteTokens, { connectionId });
556
-
557
- await ctx.runMutation(publicApi.public.disconnect, {
558
- userId: args.userId,
559
- provider: "GARMIN",
560
- });
561
-
562
- return null;
563
- },
564
- });
565
-
566
- // ─── Training API ────────────────────────────────────────────────────────────
567
-
568
- /**
569
- * Push a planned workout from Soma's DB to Garmin Connect.
570
- *
571
- * Reads the planned workout document, transforms it to Garmin Training API V2
572
- * format, creates the workout at Garmin, and optionally schedules it if a
573
- * `planned_date` is set in the metadata.
574
- *
575
- * Returns the Garmin workout ID and schedule ID (if scheduled).
576
- */
577
- export const pushPlannedWorkout = action({
578
- args: {
579
- userId: v.string(),
580
- clientId: v.string(),
581
- clientSecret: v.string(),
582
- plannedWorkoutId: v.string(),
583
- workoutProvider: v.optional(v.string()),
584
- },
585
- returns: v.object({
586
- garminWorkoutId: v.number(),
587
- garminScheduleId: v.union(v.number(), v.null()),
588
- }),
589
- handler: async (ctx, args) => {
590
- const connection = await ctx.runQuery(
591
- internalApi.private.getConnectionByProvider,
592
- { userId: args.userId, provider: "GARMIN" },
593
- );
594
- if (!connection) {
595
- throw new Error(
596
- `No Garmin connection found for user "${args.userId}". ` +
597
- "Call connectGarmin first.",
598
- );
599
- }
600
- if (!connection.active) {
601
- throw new Error(
602
- `Garmin connection for user "${args.userId}" is inactive. Reconnect first.`,
603
- );
604
- }
605
-
606
- const connectionId = connection._id;
607
-
608
- const tokenDoc = await ctx.runQuery(internalApi.garmin.getTokens, {
609
- connectionId,
610
- });
611
- if (!tokenDoc) {
612
- throw new Error(
613
- "No Garmin tokens found for this connection. " +
614
- "The connection may have been created before token storage was available.",
615
- );
616
- }
617
-
618
- // Always force-refresh the token for Training API calls to rule out
619
- // stale tokens (the initial sync swallows 401 errors silently).
620
- let accessToken = tokenDoc.accessToken;
621
-
622
- if (tokenDoc.refreshToken) {
623
- try {
624
- const refreshed = await refreshToken({
625
- clientId: args.clientId,
626
- clientSecret: args.clientSecret,
627
- refreshToken: tokenDoc.refreshToken,
628
- });
629
-
630
- accessToken = refreshed.access_token;
631
- const nowSeconds = Math.floor(Date.now() / 1000);
632
- const newExpiresAt = nowSeconds + refreshed.expires_in;
633
- await ctx.runMutation(internalApi.garmin.storeTokens, {
634
- connectionId,
635
- accessToken: refreshed.access_token,
636
- refreshToken: refreshed.refresh_token,
637
- expiresAt: newExpiresAt,
638
- });
639
- } catch (refreshErr) {
640
- throw new Error(
641
- `Garmin token refresh failed: ${refreshErr instanceof Error ? refreshErr.message : String(refreshErr)}. ` +
642
- "The user may need to reconnect their Garmin account.",
643
- );
644
- }
645
- }
646
-
647
- const plannedWorkout = await ctx.runQuery(
648
- publicApi.public.getPlannedWorkout,
649
- { plannedWorkoutId: args.plannedWorkoutId as never },
650
- );
651
- if (!plannedWorkout) {
652
- throw new Error(
653
- `Planned workout "${args.plannedWorkoutId}" not found.`,
654
- );
655
- }
656
-
657
- const providerName = args.workoutProvider ?? "Soma";
658
- const garminWorkout = transformPlannedWorkoutToGarmin(
659
- plannedWorkout,
660
- providerName,
661
- );
662
-
663
- const client = new GarminClient({ accessToken });
664
- const created = await client.createWorkout(garminWorkout);
665
-
666
- if (!created.workoutId) {
667
- throw new Error("Garmin API did not return a workoutId after creation.");
668
- }
669
-
670
- let garminScheduleId: number | null = null;
671
-
672
- const plannedDate = plannedWorkout.metadata?.planned_date;
673
- if (plannedDate) {
674
- const schedule = await client.createSchedule(
675
- created.workoutId,
676
- plannedDate,
677
- );
678
- garminScheduleId = schedule.scheduleId ?? null;
679
- }
680
-
681
- return {
682
- garminWorkoutId: created.workoutId,
683
- garminScheduleId,
684
- };
685
- },
686
- });
687
-
688
- // ─── Internal Helpers ────────────────────────────────────────────────────────
689
-
690
- interface SyncAllConfig {
691
- connectionId: string;
692
- userId: string;
693
- timeRange: { uploadStartTimeInSeconds: number; uploadEndTimeInSeconds: number };
694
- }
695
-
696
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
697
- type ActionContext = { runMutation: (ref: any, args: any) => Promise<any> };
698
-
699
- async function syncAllTypes(
700
- ctx: ActionContext,
701
- client: GarminClient,
702
- config: SyncAllConfig,
703
- ) {
704
- const { connectionId, userId, timeRange } = config;
705
-
706
- const synced = { activities: 0, dailies: 0, sleep: 0, body: 0, menstruation: 0 };
707
- const errors: Array<{ type: string; id: string; error: string }> = [];
708
-
709
- // ── Activities ──────────────────────────────────────────────────────────
710
- try {
711
- const activities = await client.getActivities(timeRange);
712
- for (const activity of activities) {
713
- try {
714
- const data = transformActivity(activity);
715
- await ctx.runMutation(publicApi.public.ingestActivity, {
716
- connectionId,
717
- userId,
718
- ...data,
719
- } as never);
720
- synced.activities++;
721
- } catch (err) {
722
- errors.push({
723
- type: "activity",
724
- id: activity.summaryId ?? String(activity.activityId),
725
- error: err instanceof Error ? err.message : String(err),
726
- });
727
- }
728
- }
729
- } catch (err) {
730
- errors.push({
731
- type: "activity",
732
- id: "fetch",
733
- error: err instanceof Error ? err.message : String(err),
734
- });
735
- }
736
-
737
- // ── Dailies ─────────────────────────────────────────────────────────────
738
- try {
739
- const dailies = await client.getDailies(timeRange);
740
- for (const daily of dailies) {
741
- try {
742
- const data = transformDaily(daily);
743
- await ctx.runMutation(publicApi.public.ingestDaily, {
744
- connectionId,
745
- userId,
746
- ...data,
747
- } as never);
748
- synced.dailies++;
749
- } catch (err) {
750
- errors.push({
751
- type: "daily",
752
- id: daily.summaryId ?? daily.calendarDate,
753
- error: err instanceof Error ? err.message : String(err),
754
- });
755
- }
756
- }
757
- } catch (err) {
758
- errors.push({
759
- type: "daily",
760
- id: "fetch",
761
- error: err instanceof Error ? err.message : String(err),
762
- });
763
- }
764
-
765
- // ── Sleep ───────────────────────────────────────────────────────────────
766
- try {
767
- const sleeps = await client.getSleeps(timeRange);
768
- for (const sleep of sleeps) {
769
- try {
770
- const data = transformSleep(sleep);
771
- await ctx.runMutation(publicApi.public.ingestSleep, {
772
- connectionId,
773
- userId,
774
- ...data,
775
- } as never);
776
- synced.sleep++;
777
- } catch (err) {
778
- errors.push({
779
- type: "sleep",
780
- id: sleep.summaryId ?? sleep.calendarDate,
781
- error: err instanceof Error ? err.message : String(err),
782
- });
783
- }
784
- }
785
- } catch (err) {
786
- errors.push({
787
- type: "sleep",
788
- id: "fetch",
789
- error: err instanceof Error ? err.message : String(err),
790
- });
791
- }
792
-
793
- // ── Body ────────────────────────────────────────────────────────────────
794
- try {
795
- const bodyComps = await client.getBodyCompositions(timeRange);
796
- for (const body of bodyComps) {
797
- try {
798
- const data = transformBody(body);
799
- await ctx.runMutation(publicApi.public.ingestBody, {
800
- connectionId,
801
- userId,
802
- ...data,
803
- } as never);
804
- synced.body++;
805
- } catch (err) {
806
- errors.push({
807
- type: "body",
808
- id: body.summaryId ?? String(body.measurementTimeInSeconds),
809
- error: err instanceof Error ? err.message : String(err),
810
- });
811
- }
812
- }
813
- } catch (err) {
814
- errors.push({
815
- type: "body",
816
- id: "fetch",
817
- error: err instanceof Error ? err.message : String(err),
818
- });
819
- }
820
-
821
- // ── Menstruation ────────────────────────────────────────────────────────
822
- try {
823
- const records = await client.getMenstrualCycleData(timeRange);
824
- for (const record of records) {
825
- try {
826
- const data = transformMenstruation(record);
827
- await ctx.runMutation(publicApi.public.ingestMenstruation, {
828
- connectionId,
829
- userId,
830
- ...data,
831
- } as never);
832
- synced.menstruation++;
833
- } catch (err) {
834
- errors.push({
835
- type: "menstruation",
836
- id: record.summaryId ?? record.calendarDate,
837
- error: err instanceof Error ? err.message : String(err),
838
- });
839
- }
840
- }
841
- } catch (err) {
842
- errors.push({
843
- type: "menstruation",
844
- id: "fetch",
845
- error: err instanceof Error ? err.message : String(err),
846
- });
847
- }
848
-
849
- return { synced, errors };
850
- }