@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,404 +1,341 @@
1
- // ─── Strava Component Actions ────────────────────────────────────────────────
2
- // Public actions that handle the full Strava OAuth + 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 { StravaClient } from "../strava/client.js";
16
- import {
17
- exchangeCode,
18
- refreshToken as refreshStravaToken,
19
- } from "../strava/auth.js";
20
- import { transformActivity } from "../strava/activity.js";
21
- import { transformAthlete } from "../strava/athlete.js";
22
-
23
- // Use anyApi to avoid circular type references between this file and _generated/api.ts.
24
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
25
- const publicApi: any = anyApi;
26
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
27
- const internalApi: any = anyApi;
28
-
29
- // ─── Internal Token CRUD ─────────────────────────────────────────────────────
30
- // These are only callable from within the component (actions in this file).
31
-
32
- /**
33
- * Store or update OAuth tokens for a connection.
34
- * Upserts by connectionId — one token record per connection.
35
- */
36
- export const storeTokens = internalMutation({
37
- args: {
38
- connectionId: v.id("connections"),
39
- accessToken: v.string(),
40
- refreshToken: v.string(),
41
- expiresAt: v.number(),
42
- },
43
- returns: v.null(),
44
- handler: async (ctx, args) => {
45
- const existing = await ctx.db
46
- .query("providerTokens")
47
- .withIndex("by_connectionId", (q) =>
48
- q.eq("connectionId", args.connectionId),
49
- )
50
- .first();
51
-
52
- if (existing) {
53
- await ctx.db.patch(existing._id, {
54
- accessToken: args.accessToken,
55
- refreshToken: args.refreshToken,
56
- expiresAt: args.expiresAt,
57
- });
58
- return null;
59
- }
60
-
61
- await ctx.db.insert("providerTokens", args);
62
- return null;
63
- },
64
- });
65
-
66
- /**
67
- * Get stored tokens for a connection.
68
- */
69
- export const getTokens = internalQuery({
70
- args: { connectionId: v.id("connections") },
71
- returns: v.union(
72
- v.object({
73
- _id: v.id("providerTokens"),
74
- _creationTime: v.number(),
75
- connectionId: v.id("connections"),
76
- accessToken: v.string(),
77
- refreshToken: v.optional(v.string()),
78
- expiresAt: v.optional(v.number()),
79
- }),
80
- v.null(),
81
- ),
82
- handler: async (ctx, args) => {
83
- return await ctx.db
84
- .query("providerTokens")
85
- .withIndex("by_connectionId", (q) =>
86
- q.eq("connectionId", args.connectionId),
87
- )
88
- .first();
89
- },
90
- });
91
-
92
- /**
93
- * Delete stored tokens for a connection.
94
- */
95
- export const deleteTokens = internalMutation({
96
- args: { connectionId: v.id("connections") },
97
- returns: v.null(),
98
- handler: async (ctx, args) => {
99
- const existing = await ctx.db
100
- .query("providerTokens")
101
- .withIndex("by_connectionId", (q) =>
102
- q.eq("connectionId", args.connectionId),
103
- )
104
- .first();
105
-
106
- if (existing) {
107
- await ctx.db.delete(existing._id);
108
- }
109
- return null;
110
- },
111
- });
112
-
113
- // ─── Public Actions ──────────────────────────────────────────────────────────
114
-
115
- /**
116
- * Full Strava OAuth callback handler.
117
- *
118
- * Exchanges the authorization code for tokens, creates/reactivates the
119
- * Soma connection, stores tokens securely, syncs the athlete profile,
120
- * and syncs all activities.
121
- *
122
- * Returns `{ connectionId, synced, errors }`.
123
- */
124
- export const connectStrava = action({
125
- args: {
126
- userId: v.string(),
127
- code: v.string(),
128
- clientId: v.string(),
129
- clientSecret: v.string(),
130
- baseUrl: v.optional(v.string()),
131
- includeStreams: v.optional(v.boolean()),
132
- },
133
- returns: v.object({
134
- connectionId: v.string(),
135
- synced: v.number(),
136
- errors: v.array(
137
- v.object({ activityId: v.number(), error: v.string() }),
138
- ),
139
- }),
140
- handler: async (ctx, args) => {
141
- // 1. Exchange authorization code for tokens
142
- const tokens = await exchangeCode({
143
- clientId: args.clientId,
144
- clientSecret: args.clientSecret,
145
- code: args.code,
146
- baseUrl: args.baseUrl,
147
- });
148
-
149
- // 2. Create/reactivate the Soma connection
150
- const connectionId = await ctx.runMutation(publicApi.public.connect, {
151
- userId: args.userId,
152
- provider: "STRAVA",
153
- });
154
-
155
- // 3. Store OAuth tokens in providerTokens table
156
- await ctx.runMutation(internalApi.strava.storeTokens, {
157
- connectionId,
158
- accessToken: tokens.access_token,
159
- refreshToken: tokens.refresh_token,
160
- expiresAt: tokens.expires_at,
161
- });
162
-
163
- // 4. Sync athlete profile
164
- const client = new StravaClient({
165
- accessToken: tokens.access_token,
166
- baseUrl: args.baseUrl,
167
- });
168
-
169
- const athlete = await client.getAthlete();
170
- const athleteData = transformAthlete(athlete);
171
- await ctx.runMutation(publicApi.public.ingestAthlete, {
172
- connectionId,
173
- userId: args.userId,
174
- ...athleteData,
175
- } as never);
176
-
177
- // 5. Sync all activities
178
- const summaries = await client.listAllActivities();
179
- let synced = 0;
180
- const errors: Array<{ activityId: number; error: string }> = [];
181
-
182
- for (const summary of summaries) {
183
- try {
184
- const detailed = await client.getActivity(summary.id);
185
- const streams = args.includeStreams
186
- ? await client.getActivityStreams(summary.id)
187
- : undefined;
188
- const data = transformActivity(detailed, { streams });
189
- await ctx.runMutation(publicApi.public.ingestActivity, {
190
- connectionId,
191
- userId: args.userId,
192
- ...data,
193
- } as never);
194
- synced++;
195
- } catch (err) {
196
- errors.push({
197
- activityId: summary.id,
198
- error: err instanceof Error ? err.message : String(err),
199
- });
200
- }
201
- }
202
-
203
- // 6. Update lastDataUpdate timestamp
204
- await ctx.runMutation(publicApi.public.updateConnection, {
205
- connectionId,
206
- lastDataUpdate: new Date().toISOString(),
207
- });
208
-
209
- return { connectionId, synced, errors };
210
- },
211
- });
212
-
213
- /**
214
- * Incremental Strava sync for an already-connected user.
215
- *
216
- * Looks up the stored tokens, auto-refreshes if expired, then syncs
217
- * the athlete profile and activities.
218
- *
219
- * Returns `{ synced, errors }`.
220
- */
221
- export const syncStrava = action({
222
- args: {
223
- userId: v.string(),
224
- clientId: v.string(),
225
- clientSecret: v.string(),
226
- baseUrl: v.optional(v.string()),
227
- includeStreams: v.optional(v.boolean()),
228
- after: v.optional(v.number()),
229
- },
230
- returns: v.object({
231
- synced: v.number(),
232
- errors: v.array(
233
- v.object({ activityId: v.number(), error: v.string() }),
234
- ),
235
- }),
236
- handler: async (ctx, args) => {
237
- // 1. Look up connection
238
- const connection = await ctx.runQuery(
239
- internalApi.private.getConnectionByProvider,
240
- { userId: args.userId, provider: "STRAVA" },
241
- );
242
- if (!connection) {
243
- throw new Error(
244
- `No Strava connection found for user "${args.userId}". ` +
245
- "Call connectStrava first.",
246
- );
247
- }
248
- if (!connection.active) {
249
- throw new Error(
250
- `Strava connection for user "${args.userId}" is inactive. Reconnect first.`,
251
- );
252
- }
253
-
254
- const connectionId = connection._id;
255
-
256
- // 2. Get stored tokens
257
- const tokenDoc = await ctx.runQuery(internalApi.strava.getTokens, {
258
- connectionId,
259
- });
260
- if (!tokenDoc) {
261
- throw new Error(
262
- `No tokens found for Strava connection. ` +
263
- "The connection may have been created before token storage was available.",
264
- );
265
- }
266
-
267
- // 3. Auto-refresh if token is expired or expiring within 5 minutes
268
- let accessToken = tokenDoc.accessToken;
269
- const now = Math.floor(Date.now() / 1000);
270
- if (!tokenDoc.refreshToken || !tokenDoc.expiresAt) {
271
- throw new Error(
272
- "Strava tokens are missing refreshToken or expiresAt. " +
273
- "This connection may have been created with an incompatible version.",
274
- );
275
- }
276
- if (tokenDoc.expiresAt < now + 300) {
277
- const refreshed = await refreshStravaToken({
278
- clientId: args.clientId,
279
- clientSecret: args.clientSecret,
280
- refreshToken: tokenDoc.refreshToken,
281
- baseUrl: args.baseUrl,
282
- });
283
- accessToken = refreshed.access_token;
284
- await ctx.runMutation(internalApi.strava.storeTokens, {
285
- connectionId,
286
- accessToken: refreshed.access_token,
287
- refreshToken: refreshed.refresh_token,
288
- expiresAt: refreshed.expires_at,
289
- });
290
- }
291
-
292
- // 4. Create client and sync
293
- const client = new StravaClient({
294
- accessToken,
295
- baseUrl: args.baseUrl,
296
- });
297
-
298
- // Sync athlete profile
299
- const athlete = await client.getAthlete();
300
- const athleteData = transformAthlete(athlete);
301
- await ctx.runMutation(publicApi.public.ingestAthlete, {
302
- connectionId,
303
- userId: args.userId,
304
- ...athleteData,
305
- } as never);
306
-
307
- // Sync activities (optionally incremental via `after`)
308
- const summaries = await client.listAllActivities({
309
- after: args.after,
310
- });
311
- let synced = 0;
312
- const errors: Array<{ activityId: number; error: string }> = [];
313
-
314
- for (const summary of summaries) {
315
- try {
316
- const detailed = await client.getActivity(summary.id);
317
- const streams = args.includeStreams
318
- ? await client.getActivityStreams(summary.id)
319
- : undefined;
320
- const data = transformActivity(detailed, { streams });
321
- await ctx.runMutation(publicApi.public.ingestActivity, {
322
- connectionId,
323
- userId: args.userId,
324
- ...data,
325
- } as never);
326
- synced++;
327
- } catch (err) {
328
- errors.push({
329
- activityId: summary.id,
330
- error: err instanceof Error ? err.message : String(err),
331
- });
332
- }
333
- }
334
-
335
- // 5. Update lastDataUpdate timestamp
336
- await ctx.runMutation(publicApi.public.updateConnection, {
337
- connectionId,
338
- lastDataUpdate: new Date().toISOString(),
339
- });
340
-
341
- return { synced, errors };
342
- },
343
- });
344
-
345
- /**
346
- * Disconnect a user from Strava.
347
- *
348
- * Revokes the token at Strava (best-effort), deletes stored tokens,
349
- * and sets the connection to inactive.
350
- */
351
- export const disconnectStrava = action({
352
- args: {
353
- userId: v.string(),
354
- clientId: v.string(),
355
- clientSecret: v.string(),
356
- baseUrl: v.optional(v.string()),
357
- },
358
- returns: v.null(),
359
- handler: async (ctx, args) => {
360
- // 1. Look up connection
361
- const connection = await ctx.runQuery(
362
- internalApi.private.getConnectionByProvider,
363
- { userId: args.userId, provider: "STRAVA" },
364
- );
365
- if (!connection) {
366
- throw new Error(
367
- `No Strava connection found for user "${args.userId}".`,
368
- );
369
- }
370
-
371
- const connectionId = connection._id;
372
-
373
- // 2. Revoke token at Strava (best-effort, don't fail if it errors)
374
- const tokenDoc = await ctx.runQuery(internalApi.strava.getTokens, {
375
- connectionId,
376
- });
377
- if (tokenDoc) {
378
- try {
379
- const base = (args.baseUrl ?? "https://www.strava.com").replace(
380
- /\/+$/,
381
- "",
382
- );
383
- await fetch(`${base}/oauth/deauthorize`, {
384
- method: "POST",
385
- headers: { "Content-Type": "application/x-www-form-urlencoded" },
386
- body: `access_token=${tokenDoc.accessToken}`,
387
- });
388
- } catch {
389
- // Deauthorization is best-effort — clean up locally regardless
390
- }
391
-
392
- // 3. Delete stored tokens
393
- await ctx.runMutation(internalApi.strava.deleteTokens, { connectionId });
394
- }
395
-
396
- // 4. Set connection inactive
397
- await ctx.runMutation(publicApi.public.disconnect, {
398
- userId: args.userId,
399
- provider: "STRAVA",
400
- });
401
-
402
- return null;
403
- },
404
- });
1
+ // ─── Strava Component Actions ────────────────────────────────────────────────
2
+ // Public actions that handle the full Strava OAuth + 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
+ import { v } from "convex/values";
7
+ import { action } from "../_generated/server";
8
+ import { api, internal } from "../_generated/api";
9
+ import type { Doc, Id } from "../_generated/dataModel";
10
+ import { StravaClient } from "../../strava/client";
11
+ import {
12
+ exchangeCode,
13
+ refreshToken as refreshStravaToken,
14
+ } from "../../strava/auth";
15
+ import { transformActivity } from "../../strava/activity";
16
+ import { transformAthlete } from "../../strava/athlete";
17
+
18
+ // ─── Public Actions ──────────────────────────────────────────────────────────
19
+
20
+ /**
21
+ * Full Strava OAuth callback handler.
22
+ *
23
+ * Exchanges the authorization code for tokens, creates/reactivates the
24
+ * Soma connection, stores tokens securely, syncs the athlete profile,
25
+ * and syncs all activities.
26
+ *
27
+ * Returns `{ connectionId, synced, errors }`.
28
+ */
29
+ export const connectStrava = action({
30
+ args: {
31
+ userId: v.string(),
32
+ code: v.string(),
33
+ clientId: v.string(),
34
+ clientSecret: v.string(),
35
+ baseUrl: v.optional(v.string()),
36
+ includeStreams: v.optional(v.boolean()),
37
+ },
38
+ returns: v.object({
39
+ connectionId: v.string(),
40
+ synced: v.number(),
41
+ errors: v.array(
42
+ v.object({ activityId: v.number(), error: v.string() }),
43
+ ),
44
+ }),
45
+ handler: async (ctx, args) => {
46
+ // 1. Exchange authorization code for tokens
47
+ const tokens = await exchangeCode({
48
+ clientId: args.clientId,
49
+ clientSecret: args.clientSecret,
50
+ code: args.code,
51
+ baseUrl: args.baseUrl,
52
+ });
53
+
54
+ // 2. Create/reactivate the Soma connection
55
+ const connectionId: Id<"connections"> = await ctx.runMutation(
56
+ api.public.connect,
57
+ {
58
+ userId: args.userId,
59
+ provider: "STRAVA",
60
+ },
61
+ );
62
+
63
+ // 3. Store OAuth tokens in providerTokens table
64
+ const _stored: null = await ctx.runMutation(
65
+ internal.strava.private.storeTokens,
66
+ {
67
+ connectionId,
68
+ accessToken: tokens.access_token,
69
+ refreshToken: tokens.refresh_token,
70
+ expiresAt: tokens.expires_at,
71
+ },
72
+ );
73
+
74
+ // 4. Sync athlete profile
75
+ const client = new StravaClient({
76
+ accessToken: tokens.access_token,
77
+ baseUrl: args.baseUrl,
78
+ });
79
+
80
+ const athlete = await client.getAthlete();
81
+ const athleteData = transformAthlete(athlete);
82
+ const _athleteId: Id<"athletes"> = await ctx.runMutation(
83
+ api.public.ingestAthlete,
84
+ {
85
+ connectionId,
86
+ userId: args.userId,
87
+ ...athleteData,
88
+ } as never,
89
+ );
90
+
91
+ // 5. Sync all activities
92
+ const summaries = await client.listAllActivities();
93
+ let synced = 0;
94
+ const errors: Array<{ activityId: number; error: string }> = [];
95
+
96
+ for (const summary of summaries) {
97
+ try {
98
+ const detailed = await client.getActivity(summary.id);
99
+ const streams = args.includeStreams
100
+ ? await client.getActivityStreams(summary.id)
101
+ : undefined;
102
+ const data = transformActivity(detailed, { streams });
103
+ const _activityId: Id<"activities"> = await ctx.runMutation(
104
+ api.public.ingestActivity,
105
+ {
106
+ connectionId,
107
+ userId: args.userId,
108
+ ...data,
109
+ } as never,
110
+ );
111
+ synced++;
112
+ } catch (err) {
113
+ errors.push({
114
+ activityId: summary.id,
115
+ error: err instanceof Error ? err.message : String(err),
116
+ });
117
+ }
118
+ }
119
+
120
+ // 6. Update lastDataUpdate timestamp
121
+ const _updated: null = await ctx.runMutation(
122
+ api.public.updateConnection,
123
+ {
124
+ connectionId,
125
+ lastDataUpdate: new Date().toISOString(),
126
+ },
127
+ );
128
+
129
+ return { connectionId, synced, errors };
130
+ },
131
+ });
132
+
133
+ /**
134
+ * Incremental Strava sync for an already-connected user.
135
+ *
136
+ * Looks up the stored tokens, auto-refreshes if expired, then syncs
137
+ * the athlete profile and activities.
138
+ *
139
+ * Returns `{ synced, errors }`.
140
+ */
141
+ export const syncStrava = action({
142
+ args: {
143
+ userId: v.string(),
144
+ clientId: v.string(),
145
+ clientSecret: v.string(),
146
+ baseUrl: v.optional(v.string()),
147
+ includeStreams: v.optional(v.boolean()),
148
+ after: v.optional(v.number()),
149
+ },
150
+ returns: v.object({
151
+ synced: v.number(),
152
+ errors: v.array(
153
+ v.object({ activityId: v.number(), error: v.string() }),
154
+ ),
155
+ }),
156
+ handler: async (ctx, args) => {
157
+ // 1. Look up connection
158
+ const connection: Doc<"connections"> | null = await ctx.runQuery(
159
+ internal.private.getConnectionByProvider,
160
+ { userId: args.userId, provider: "STRAVA" },
161
+ );
162
+ if (!connection) {
163
+ throw new Error(
164
+ `No Strava connection found for user "${args.userId}". ` +
165
+ "Call connectStrava first.",
166
+ );
167
+ }
168
+ if (!connection.active) {
169
+ throw new Error(
170
+ `Strava connection for user "${args.userId}" is inactive. Reconnect first.`,
171
+ );
172
+ }
173
+
174
+ const connectionId = connection._id;
175
+
176
+ // 2. Get stored tokens
177
+ const tokenDoc: Doc<"providerTokens"> | null = await ctx.runQuery(
178
+ internal.strava.private.getTokens,
179
+ { connectionId },
180
+ );
181
+ if (!tokenDoc) {
182
+ throw new Error(
183
+ `No tokens found for Strava connection. ` +
184
+ "The connection may have been created before token storage was available.",
185
+ );
186
+ }
187
+
188
+ // 3. Auto-refresh if token is expired or expiring within 5 minutes
189
+ let accessToken = tokenDoc.accessToken;
190
+ const now = Math.floor(Date.now() / 1000);
191
+ if (!tokenDoc.refreshToken || !tokenDoc.expiresAt) {
192
+ throw new Error(
193
+ "Strava tokens are missing refreshToken or expiresAt. " +
194
+ "This connection may have been created with an incompatible version.",
195
+ );
196
+ }
197
+ if (tokenDoc.expiresAt < now + 300) {
198
+ const refreshed = await refreshStravaToken({
199
+ clientId: args.clientId,
200
+ clientSecret: args.clientSecret,
201
+ refreshToken: tokenDoc.refreshToken,
202
+ baseUrl: args.baseUrl,
203
+ });
204
+ accessToken = refreshed.access_token;
205
+ const _refreshed: null = await ctx.runMutation(
206
+ internal.strava.private.storeTokens,
207
+ {
208
+ connectionId,
209
+ accessToken: refreshed.access_token,
210
+ refreshToken: refreshed.refresh_token,
211
+ expiresAt: refreshed.expires_at,
212
+ },
213
+ );
214
+ }
215
+
216
+ // 4. Create client and sync
217
+ const client = new StravaClient({
218
+ accessToken,
219
+ baseUrl: args.baseUrl,
220
+ });
221
+
222
+ // Sync athlete profile
223
+ const athlete = await client.getAthlete();
224
+ const athleteData = transformAthlete(athlete);
225
+ const _athleteId: Id<"athletes"> = await ctx.runMutation(
226
+ api.public.ingestAthlete,
227
+ {
228
+ connectionId,
229
+ userId: args.userId,
230
+ ...athleteData,
231
+ } as never,
232
+ );
233
+
234
+ // Sync activities (optionally incremental via `after`)
235
+ const summaries = await client.listAllActivities({
236
+ after: args.after,
237
+ });
238
+ let synced = 0;
239
+ const errors: Array<{ activityId: number; error: string }> = [];
240
+
241
+ for (const summary of summaries) {
242
+ try {
243
+ const detailed = await client.getActivity(summary.id);
244
+ const streams = args.includeStreams
245
+ ? await client.getActivityStreams(summary.id)
246
+ : undefined;
247
+ const data = transformActivity(detailed, { streams });
248
+ const _activityId: Id<"activities"> = await ctx.runMutation(
249
+ api.public.ingestActivity,
250
+ {
251
+ connectionId,
252
+ userId: args.userId,
253
+ ...data,
254
+ } as never,
255
+ );
256
+ synced++;
257
+ } catch (err) {
258
+ errors.push({
259
+ activityId: summary.id,
260
+ error: err instanceof Error ? err.message : String(err),
261
+ });
262
+ }
263
+ }
264
+
265
+ // 5. Update lastDataUpdate timestamp
266
+ const _updated: null = await ctx.runMutation(
267
+ api.public.updateConnection,
268
+ {
269
+ connectionId,
270
+ lastDataUpdate: new Date().toISOString(),
271
+ },
272
+ );
273
+
274
+ return { synced, errors };
275
+ },
276
+ });
277
+
278
+ /**
279
+ * Disconnect a user from Strava.
280
+ *
281
+ * Revokes the token at Strava (best-effort), deletes stored tokens,
282
+ * and sets the connection to inactive.
283
+ */
284
+ export const disconnectStrava = action({
285
+ args: {
286
+ userId: v.string(),
287
+ clientId: v.string(),
288
+ clientSecret: v.string(),
289
+ baseUrl: v.optional(v.string()),
290
+ },
291
+ returns: v.null(),
292
+ handler: async (ctx, args) => {
293
+ // 1. Look up connection
294
+ const connection: Doc<"connections"> | null = await ctx.runQuery(
295
+ internal.private.getConnectionByProvider,
296
+ { userId: args.userId, provider: "STRAVA" },
297
+ );
298
+ if (!connection) {
299
+ throw new Error(
300
+ `No Strava connection found for user "${args.userId}".`,
301
+ );
302
+ }
303
+
304
+ const connectionId = connection._id;
305
+
306
+ // 2. Revoke token at Strava (best-effort, don't fail if it errors)
307
+ const tokenDoc: Doc<"providerTokens"> | null = await ctx.runQuery(
308
+ internal.strava.private.getTokens,
309
+ { connectionId },
310
+ );
311
+ if (tokenDoc) {
312
+ try {
313
+ const base = (args.baseUrl ?? "https://www.strava.com").replace(
314
+ /\/+$/,
315
+ "",
316
+ );
317
+ await fetch(`${base}/oauth/deauthorize`, {
318
+ method: "POST",
319
+ headers: { "Content-Type": "application/x-www-form-urlencoded" },
320
+ body: `access_token=${tokenDoc.accessToken}`,
321
+ });
322
+ } catch {
323
+ // Deauthorization is best-effort — clean up locally regardless
324
+ }
325
+
326
+ // 3. Delete stored tokens
327
+ const _deleted: null = await ctx.runMutation(
328
+ internal.strava.private.deleteTokens,
329
+ { connectionId },
330
+ );
331
+ }
332
+
333
+ // 4. Set connection inactive
334
+ const _disconnected: null = await ctx.runMutation(api.public.disconnect, {
335
+ userId: args.userId,
336
+ provider: "STRAVA",
337
+ });
338
+
339
+ return null;
340
+ },
341
+ });