@nativesquare/soma 0.12.0 → 0.13.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 (60) hide show
  1. package/dist/client/garmin.d.ts +5 -1
  2. package/dist/client/garmin.d.ts.map +1 -1
  3. package/dist/client/garmin.js +148 -0
  4. package/dist/client/garmin.js.map +1 -1
  5. package/dist/client/index.d.ts +5 -6
  6. package/dist/client/index.d.ts.map +1 -1
  7. package/dist/client/index.js +5 -211
  8. package/dist/client/index.js.map +1 -1
  9. package/dist/client/strava.d.ts +11 -6
  10. package/dist/client/strava.d.ts.map +1 -1
  11. package/dist/client/strava.js +64 -0
  12. package/dist/client/strava.js.map +1 -1
  13. package/dist/client/types.d.ts +93 -20
  14. package/dist/client/types.d.ts.map +1 -1
  15. package/dist/component/_generated/component.d.ts +24 -5
  16. package/dist/component/_generated/component.d.ts.map +1 -1
  17. package/dist/component/garmin/private.d.ts +53 -68
  18. package/dist/component/garmin/private.d.ts.map +1 -1
  19. package/dist/component/garmin/private.js +87 -85
  20. package/dist/component/garmin/private.js.map +1 -1
  21. package/dist/component/garmin/public.d.ts +97 -43
  22. package/dist/component/garmin/public.d.ts.map +1 -1
  23. package/dist/component/garmin/public.js +75 -51
  24. package/dist/component/garmin/public.js.map +1 -1
  25. package/dist/component/garmin/webhooks.d.ts +22 -20
  26. package/dist/component/garmin/webhooks.d.ts.map +1 -1
  27. package/dist/component/garmin/webhooks.js +115 -76
  28. package/dist/component/garmin/webhooks.js.map +1 -1
  29. package/dist/component/public.d.ts +15 -15
  30. package/dist/component/schema.d.ts +25 -25
  31. package/dist/component/strava/public.d.ts +12 -8
  32. package/dist/component/strava/public.d.ts.map +1 -1
  33. package/dist/component/strava/public.js +7 -7
  34. package/dist/component/strava/public.js.map +1 -1
  35. package/dist/component/validators/activity.d.ts +4 -4
  36. package/dist/component/validators/body.d.ts +4 -4
  37. package/dist/component/validators/daily.d.ts +4 -4
  38. package/dist/component/validators/nutrition.d.ts +3 -3
  39. package/dist/component/validators/samples.d.ts +4 -4
  40. package/dist/component/validators/shared.d.ts +13 -4
  41. package/dist/component/validators/shared.d.ts.map +1 -1
  42. package/dist/component/validators/shared.js +7 -0
  43. package/dist/component/validators/shared.js.map +1 -1
  44. package/dist/component/validators/sleep.d.ts +5 -5
  45. package/dist/validators.d.ts +41 -40
  46. package/dist/validators.d.ts.map +1 -1
  47. package/dist/validators.js +1 -0
  48. package/dist/validators.js.map +1 -1
  49. package/package.json +1 -1
  50. package/src/client/garmin.ts +692 -487
  51. package/src/client/index.ts +10 -279
  52. package/src/client/strava.ts +199 -108
  53. package/src/client/types.ts +303 -215
  54. package/src/component/_generated/component.ts +19 -19
  55. package/src/component/garmin/private.ts +1872 -1870
  56. package/src/component/garmin/public.ts +104 -80
  57. package/src/component/garmin/webhooks.ts +122 -81
  58. package/src/component/strava/public.ts +393 -393
  59. package/src/component/validators/shared.ts +9 -0
  60. package/src/validators.ts +1 -0
@@ -227,7 +227,7 @@ export const pullActivities = action({
227
227
 
228
228
  const wellnessClient = createWellnessClient(accessToken);
229
229
  const synced = { activities: 0 };
230
- const errors: Array<{ type: "activity"; id: string; error: string }> = [];
230
+ const errors: Array<{ type: string; id: string; message: string }> = [];
231
231
 
232
232
  try {
233
233
  const { data: activities, error } = await getActivities({
@@ -252,7 +252,7 @@ export const pullActivities = action({
252
252
  errors.push({
253
253
  type: "activity",
254
254
  id: activity.summaryId ?? String(activity.activityId),
255
- error: err instanceof Error ? err.message : String(err),
255
+ message: err instanceof Error ? err.message : String(err),
256
256
  });
257
257
  }
258
258
  }
@@ -260,7 +260,7 @@ export const pullActivities = action({
260
260
  errors.push({
261
261
  type: "activity",
262
262
  id: "fetch",
263
- error: err instanceof Error ? err.message : String(err),
263
+ message: err instanceof Error ? err.message : String(err),
264
264
  });
265
265
  }
266
266
 
@@ -269,7 +269,7 @@ export const pullActivities = action({
269
269
  lastDataUpdate: new Date().toISOString(),
270
270
  });
271
271
 
272
- return { synced, errors };
272
+ return { data: { synced }, errors };
273
273
  },
274
274
  });
275
275
 
@@ -290,7 +290,7 @@ export const pullDailies = action({
290
290
  const query = buildTimeRangeQuery(args, accessToken);
291
291
  const wellnessClient = createWellnessClient(accessToken);
292
292
  const synced = { dailies: 0 };
293
- const errors: Array<{ type: string; id: string; error: string }> = [];
293
+ const errors: Array<{ type: string; id: string; message: string }> = [];
294
294
 
295
295
  try {
296
296
  const { data: dailies, error } = await getDailies({ client: wellnessClient, query });
@@ -302,15 +302,15 @@ export const pullDailies = action({
302
302
  await ctx.runMutation(api.public.ingestDaily, { connectionId, userId: args.userId, ...data });
303
303
  synced.dailies++;
304
304
  } catch (err) {
305
- errors.push({ type: "daily", id: daily.summaryId ?? daily.calendarDate ?? "unknown", error: err instanceof Error ? err.message : String(err) });
305
+ errors.push({ type: "daily", id: daily.summaryId ?? daily.calendarDate ?? "unknown", message: err instanceof Error ? err.message : String(err) });
306
306
  }
307
307
  }
308
308
  } catch (err) {
309
- errors.push({ type: "daily", id: "fetch", error: err instanceof Error ? err.message : String(err) });
309
+ errors.push({ type: "daily", id: "fetch", message: err instanceof Error ? err.message : String(err) });
310
310
  }
311
311
 
312
312
  await ctx.runMutation(api.public.updateConnection, { connectionId, lastDataUpdate: new Date().toISOString() });
313
- return { synced, errors };
313
+ return { data: { synced }, errors };
314
314
  },
315
315
  });
316
316
 
@@ -331,7 +331,7 @@ export const pullSleep = action({
331
331
  const query = buildTimeRangeQuery(args, accessToken);
332
332
  const wellnessClient = createWellnessClient(accessToken);
333
333
  const synced = { sleep: 0 };
334
- const errors: Array<{ type: string; id: string; error: string }> = [];
334
+ const errors: Array<{ type: string; id: string; message: string }> = [];
335
335
 
336
336
  try {
337
337
  const { data: sleeps, error } = await getSleeps({ client: wellnessClient, query });
@@ -342,15 +342,15 @@ export const pullSleep = action({
342
342
  await ctx.runMutation(api.public.ingestSleep, { connectionId, userId: args.userId, ...data });
343
343
  synced.sleep++;
344
344
  } catch (err) {
345
- errors.push({ type: "sleep", id: sleep.summaryId ?? sleep.calendarDate ?? "unknown", error: err instanceof Error ? err.message : String(err) });
345
+ errors.push({ type: "sleep", id: sleep.summaryId ?? sleep.calendarDate ?? "unknown", message: err instanceof Error ? err.message : String(err) });
346
346
  }
347
347
  }
348
348
  } catch (err) {
349
- errors.push({ type: "sleep", id: "fetch", error: err instanceof Error ? err.message : String(err) });
349
+ errors.push({ type: "sleep", id: "fetch", message: err instanceof Error ? err.message : String(err) });
350
350
  }
351
351
 
352
352
  await ctx.runMutation(api.public.updateConnection, { connectionId, lastDataUpdate: new Date().toISOString() });
353
- return { synced, errors };
353
+ return { data: { synced }, errors };
354
354
  },
355
355
  });
356
356
 
@@ -371,7 +371,7 @@ export const pullBody = action({
371
371
  const query = buildTimeRangeQuery(args, accessToken);
372
372
  const wellnessClient = createWellnessClient(accessToken);
373
373
  const synced = { body: 0 };
374
- const errors: Array<{ type: string; id: string; error: string }> = [];
374
+ const errors: Array<{ type: string; id: string; message: string }> = [];
375
375
 
376
376
  try {
377
377
  const { data: bodyComps, error } = await getBodyComps({ client: wellnessClient, query });
@@ -383,15 +383,15 @@ export const pullBody = action({
383
383
  await ctx.runMutation(api.public.ingestBody, { connectionId, userId: args.userId, ...data });
384
384
  synced.body++;
385
385
  } catch (err) {
386
- errors.push({ type: "body", id: body.summaryId ?? String(body.measurementTimeInSeconds), error: err instanceof Error ? err.message : String(err) });
386
+ errors.push({ type: "body", id: body.summaryId ?? String(body.measurementTimeInSeconds), message: err instanceof Error ? err.message : String(err) });
387
387
  }
388
388
  }
389
389
  } catch (err) {
390
- errors.push({ type: "body", id: "fetch", error: err instanceof Error ? err.message : String(err) });
390
+ errors.push({ type: "body", id: "fetch", message: err instanceof Error ? err.message : String(err) });
391
391
  }
392
392
 
393
393
  await ctx.runMutation(api.public.updateConnection, { connectionId, lastDataUpdate: new Date().toISOString() });
394
- return { synced, errors };
394
+ return { data: { synced }, errors };
395
395
  },
396
396
  });
397
397
 
@@ -412,7 +412,7 @@ export const pullMenstruation = action({
412
412
  const query = buildTimeRangeQuery(args, accessToken);
413
413
  const wellnessClient = createWellnessClient(accessToken);
414
414
  const synced = { menstruation: 0 };
415
- const errors: Array<{ type: string; id: string; error: string }> = [];
415
+ const errors: Array<{ type: string; id: string; message: string }> = [];
416
416
 
417
417
  try {
418
418
  const { data: records, error } = await getMct({ client: wellnessClient, query });
@@ -423,15 +423,15 @@ export const pullMenstruation = action({
423
423
  await ctx.runMutation(api.public.ingestMenstruation, { connectionId, userId: args.userId, ...data });
424
424
  synced.menstruation++;
425
425
  } catch (err) {
426
- errors.push({ type: "menstruation", id: record.summaryId ?? record.periodStartDate ?? "unknown", error: err instanceof Error ? err.message : String(err) });
426
+ errors.push({ type: "menstruation", id: record.summaryId ?? record.periodStartDate ?? "unknown", message: err instanceof Error ? err.message : String(err) });
427
427
  }
428
428
  }
429
429
  } catch (err) {
430
- errors.push({ type: "menstruation", id: "fetch", error: err instanceof Error ? err.message : String(err) });
430
+ errors.push({ type: "menstruation", id: "fetch", message: err instanceof Error ? err.message : String(err) });
431
431
  }
432
432
 
433
433
  await ctx.runMutation(api.public.updateConnection, { connectionId, lastDataUpdate: new Date().toISOString() });
434
- return { synced, errors };
434
+ return { data: { synced }, errors };
435
435
  },
436
436
  });
437
437
 
@@ -452,7 +452,7 @@ export const pullBloodPressures = action({
452
452
  const query = buildTimeRangeQuery(args, accessToken);
453
453
  const wellnessClient = createWellnessClient(accessToken);
454
454
  const synced = { bloodPressures: 0 };
455
- const errors: Array<{ type: string; id: string; error: string }> = [];
455
+ const errors: Array<{ type: string; id: string; message: string }> = [];
456
456
 
457
457
  try {
458
458
  const { data: bpRecords, error } = await getBloodPressures({ client: wellnessClient, query });
@@ -464,15 +464,15 @@ export const pullBloodPressures = action({
464
464
  await ctx.runMutation(api.public.ingestBody, { connectionId, userId: args.userId, ...data });
465
465
  synced.bloodPressures++;
466
466
  } catch (err) {
467
- errors.push({ type: "bloodPressure", id: bp.summaryId ?? String(bp.measurementTimeInSeconds), error: err instanceof Error ? err.message : String(err) });
467
+ errors.push({ type: "bloodPressure", id: bp.summaryId ?? String(bp.measurementTimeInSeconds), message: err instanceof Error ? err.message : String(err) });
468
468
  }
469
469
  }
470
470
  } catch (err) {
471
- errors.push({ type: "bloodPressure", id: "fetch", error: err instanceof Error ? err.message : String(err) });
471
+ errors.push({ type: "bloodPressure", id: "fetch", message: err instanceof Error ? err.message : String(err) });
472
472
  }
473
473
 
474
474
  await ctx.runMutation(api.public.updateConnection, { connectionId, lastDataUpdate: new Date().toISOString() });
475
- return { synced, errors };
475
+ return { data: { synced }, errors };
476
476
  },
477
477
  });
478
478
 
@@ -493,7 +493,7 @@ export const pullSkinTemperature = action({
493
493
  const query = buildTimeRangeQuery(args, accessToken);
494
494
  const wellnessClient = createWellnessClient(accessToken);
495
495
  const synced = { skinTemp: 0 };
496
- const errors: Array<{ type: string; id: string; error: string }> = [];
496
+ const errors: Array<{ type: string; id: string; message: string }> = [];
497
497
 
498
498
  try {
499
499
  const { data: skinRecords, error } = await getSkinTemp({ client: wellnessClient, query });
@@ -505,15 +505,15 @@ export const pullSkinTemperature = action({
505
505
  await ctx.runMutation(api.public.ingestBody, { connectionId, userId: args.userId, ...data });
506
506
  synced.skinTemp++;
507
507
  } catch (err) {
508
- errors.push({ type: "skinTemp", id: skin.summaryId ?? skin.calendarDate ?? "unknown", error: err instanceof Error ? err.message : String(err) });
508
+ errors.push({ type: "skinTemp", id: skin.summaryId ?? skin.calendarDate ?? "unknown", message: err instanceof Error ? err.message : String(err) });
509
509
  }
510
510
  }
511
511
  } catch (err) {
512
- errors.push({ type: "skinTemp", id: "fetch", error: err instanceof Error ? err.message : String(err) });
512
+ errors.push({ type: "skinTemp", id: "fetch", message: err instanceof Error ? err.message : String(err) });
513
513
  }
514
514
 
515
515
  await ctx.runMutation(api.public.updateConnection, { connectionId, lastDataUpdate: new Date().toISOString() });
516
- return { synced, errors };
516
+ return { data: { synced }, errors };
517
517
  },
518
518
  });
519
519
 
@@ -534,7 +534,7 @@ export const pullUserMetrics = action({
534
534
  const query = buildTimeRangeQuery(args, accessToken);
535
535
  const wellnessClient = createWellnessClient(accessToken);
536
536
  const synced = { userMetrics: 0 };
537
- const errors: Array<{ type: string; id: string; error: string }> = [];
537
+ const errors: Array<{ type: string; id: string; message: string }> = [];
538
538
 
539
539
  try {
540
540
  const { data: metricsRecords, error } = await getUserMetrics({ client: wellnessClient, query });
@@ -546,15 +546,15 @@ export const pullUserMetrics = action({
546
546
  await ctx.runMutation(api.public.ingestBody, { connectionId, userId: args.userId, ...data });
547
547
  synced.userMetrics++;
548
548
  } catch (err) {
549
- errors.push({ type: "userMetrics", id: metrics.summaryId ?? metrics.calendarDate ?? "unknown", error: err instanceof Error ? err.message : String(err) });
549
+ errors.push({ type: "userMetrics", id: metrics.summaryId ?? metrics.calendarDate ?? "unknown", message: err instanceof Error ? err.message : String(err) });
550
550
  }
551
551
  }
552
552
  } catch (err) {
553
- errors.push({ type: "userMetrics", id: "fetch", error: err instanceof Error ? err.message : String(err) });
553
+ errors.push({ type: "userMetrics", id: "fetch", message: err instanceof Error ? err.message : String(err) });
554
554
  }
555
555
 
556
556
  await ctx.runMutation(api.public.updateConnection, { connectionId, lastDataUpdate: new Date().toISOString() });
557
- return { synced, errors };
557
+ return { data: { synced }, errors };
558
558
  },
559
559
  });
560
560
 
@@ -575,7 +575,7 @@ export const pullHRV = action({
575
575
  const query = buildTimeRangeQuery(args, accessToken);
576
576
  const wellnessClient = createWellnessClient(accessToken);
577
577
  const synced = { hrv: 0 };
578
- const errors: Array<{ type: string; id: string; error: string }> = [];
578
+ const errors: Array<{ type: string; id: string; message: string }> = [];
579
579
 
580
580
  try {
581
581
  const { data: hrvRecords, error } = await getHrv({ client: wellnessClient, query });
@@ -587,15 +587,15 @@ export const pullHRV = action({
587
587
  await ctx.runMutation(api.public.ingestDaily, { connectionId, userId: args.userId, ...data });
588
588
  synced.hrv++;
589
589
  } catch (err) {
590
- errors.push({ type: "hrv", id: hrv.summaryId ?? hrv.calendarDate ?? "unknown", error: err instanceof Error ? err.message : String(err) });
590
+ errors.push({ type: "hrv", id: hrv.summaryId ?? hrv.calendarDate ?? "unknown", message: err instanceof Error ? err.message : String(err) });
591
591
  }
592
592
  }
593
593
  } catch (err) {
594
- errors.push({ type: "hrv", id: "fetch", error: err instanceof Error ? err.message : String(err) });
594
+ errors.push({ type: "hrv", id: "fetch", message: err instanceof Error ? err.message : String(err) });
595
595
  }
596
596
 
597
597
  await ctx.runMutation(api.public.updateConnection, { connectionId, lastDataUpdate: new Date().toISOString() });
598
- return { synced, errors };
598
+ return { data: { synced }, errors };
599
599
  },
600
600
  });
601
601
 
@@ -616,7 +616,7 @@ export const pullStressDetails = action({
616
616
  const query = buildTimeRangeQuery(args, accessToken);
617
617
  const wellnessClient = createWellnessClient(accessToken);
618
618
  const synced = { stressDetails: 0 };
619
- const errors: Array<{ type: string; id: string; error: string }> = [];
619
+ const errors: Array<{ type: string; id: string; message: string }> = [];
620
620
 
621
621
  try {
622
622
  const { data: stressRecords, error } = await getStressDetails({ client: wellnessClient, query });
@@ -628,15 +628,15 @@ export const pullStressDetails = action({
628
628
  await ctx.runMutation(api.public.ingestDaily, { connectionId, userId: args.userId, ...data });
629
629
  synced.stressDetails++;
630
630
  } catch (err) {
631
- errors.push({ type: "stressDetails", id: stress.summaryId ?? stress.calendarDate ?? "unknown", error: err instanceof Error ? err.message : String(err) });
631
+ errors.push({ type: "stressDetails", id: stress.summaryId ?? stress.calendarDate ?? "unknown", message: err instanceof Error ? err.message : String(err) });
632
632
  }
633
633
  }
634
634
  } catch (err) {
635
- errors.push({ type: "stressDetails", id: "fetch", error: err instanceof Error ? err.message : String(err) });
635
+ errors.push({ type: "stressDetails", id: "fetch", message: err instanceof Error ? err.message : String(err) });
636
636
  }
637
637
 
638
638
  await ctx.runMutation(api.public.updateConnection, { connectionId, lastDataUpdate: new Date().toISOString() });
639
- return { synced, errors };
639
+ return { data: { synced }, errors };
640
640
  },
641
641
  });
642
642
 
@@ -657,7 +657,7 @@ export const pullPulseOx = action({
657
657
  const query = buildTimeRangeQuery(args, accessToken);
658
658
  const wellnessClient = createWellnessClient(accessToken);
659
659
  const synced = { pulseOx: 0 };
660
- const errors: Array<{ type: string; id: string; error: string }> = [];
660
+ const errors: Array<{ type: string; id: string; message: string }> = [];
661
661
 
662
662
  try {
663
663
  const { data: pulseOxRecords, error } = await getPulseox({ client: wellnessClient, query });
@@ -669,15 +669,15 @@ export const pullPulseOx = action({
669
669
  await ctx.runMutation(api.public.ingestDaily, { connectionId, userId: args.userId, ...data });
670
670
  synced.pulseOx++;
671
671
  } catch (err) {
672
- errors.push({ type: "pulseOx", id: po.summaryId ?? po.calendarDate ?? "unknown", error: err instanceof Error ? err.message : String(err) });
672
+ errors.push({ type: "pulseOx", id: po.summaryId ?? po.calendarDate ?? "unknown", message: err instanceof Error ? err.message : String(err) });
673
673
  }
674
674
  }
675
675
  } catch (err) {
676
- errors.push({ type: "pulseOx", id: "fetch", error: err instanceof Error ? err.message : String(err) });
676
+ errors.push({ type: "pulseOx", id: "fetch", message: err instanceof Error ? err.message : String(err) });
677
677
  }
678
678
 
679
679
  await ctx.runMutation(api.public.updateConnection, { connectionId, lastDataUpdate: new Date().toISOString() });
680
- return { synced, errors };
680
+ return { data: { synced }, errors };
681
681
  },
682
682
  });
683
683
 
@@ -698,7 +698,7 @@ export const pullRespiration = action({
698
698
  const query = buildTimeRangeQuery(args, accessToken);
699
699
  const wellnessClient = createWellnessClient(accessToken);
700
700
  const synced = { respiration: 0 };
701
- const errors: Array<{ type: string; id: string; error: string }> = [];
701
+ const errors: Array<{ type: string; id: string; message: string }> = [];
702
702
 
703
703
  try {
704
704
  const { data: respRecords, error } = await getRespiration({ client: wellnessClient, query });
@@ -710,15 +710,15 @@ export const pullRespiration = action({
710
710
  await ctx.runMutation(api.public.ingestDaily, { connectionId, userId: args.userId, ...data });
711
711
  synced.respiration++;
712
712
  } catch (err) {
713
- errors.push({ type: "respiration", id: resp.summaryId ?? "unknown", error: err instanceof Error ? err.message : String(err) });
713
+ errors.push({ type: "respiration", id: resp.summaryId ?? "unknown", message: err instanceof Error ? err.message : String(err) });
714
714
  }
715
715
  }
716
716
  } catch (err) {
717
- errors.push({ type: "respiration", id: "fetch", error: err instanceof Error ? err.message : String(err) });
717
+ errors.push({ type: "respiration", id: "fetch", message: err instanceof Error ? err.message : String(err) });
718
718
  }
719
719
 
720
720
  await ctx.runMutation(api.public.updateConnection, { connectionId, lastDataUpdate: new Date().toISOString() });
721
- return { synced, errors };
721
+ return { data: { synced }, errors };
722
722
  },
723
723
  });
724
724
 
@@ -753,21 +753,21 @@ export const pullAll = action({
753
753
  { ref: api.garmin.public.pullRespiration, name: "respiration" },
754
754
  ];
755
755
  const synced: Record<string, number> = {};
756
- const errors: Array<{ type: string; id: string; error: string }> = [];
756
+ const errors: Array<{ type: string; id: string; message: string }> = [];
757
757
  for (const { ref, name } of pullFns) {
758
758
  try {
759
759
  const result = await ctx.runAction(ref, sharedArgs);
760
- Object.assign(synced, result.synced);
760
+ Object.assign(synced, result.data.synced);
761
761
  errors.push(...result.errors);
762
762
  } catch (err) {
763
763
  errors.push({
764
764
  type: name,
765
765
  id: "pull",
766
- error: err instanceof Error ? err.message : String(err),
766
+ message: err instanceof Error ? err.message : String(err),
767
767
  });
768
768
  }
769
769
  }
770
- return { synced, errors };
770
+ return { data: { synced }, errors };
771
771
  },
772
772
  });
773
773
 
@@ -782,7 +782,10 @@ export const pushWorkout = action({
782
782
  plannedWorkoutId: v.string(),
783
783
  workoutProvider: v.optional(v.string()),
784
784
  },
785
- handler: async (ctx, args): Promise<{ garminWorkoutId: number }> => {
785
+ handler: async (ctx, args): Promise<{
786
+ data: { garminWorkoutId: number } | null;
787
+ errors: Array<{ type: string; id: string; message: string }>;
788
+ }> => {
786
789
  const { connectionId, accessToken } = await ctx.runAction(
787
790
  internal.garmin.private.resolveConnectionAndAccessToken,
788
791
  { userId: args.userId, clientId: args.clientId, clientSecret: args.clientSecret },
@@ -814,9 +817,10 @@ export const pushWorkout = action({
814
817
  path: { workoutId: numericId },
815
818
  });
816
819
  if (updateError) {
817
- throw new Error(
818
- `Garmin API error updating workout: ${JSON.stringify(updateError)}`,
819
- );
820
+ return {
821
+ data: null,
822
+ errors: [{ type: "pushWorkout", id: args.plannedWorkoutId, message: `Garmin API error updating workout: ${JSON.stringify(updateError)}` }],
823
+ };
820
824
  }
821
825
  workoutId = numericId;
822
826
  } else {
@@ -826,12 +830,16 @@ export const pushWorkout = action({
826
830
  body: garminWorkout,
827
831
  });
828
832
  if (createError || !created) {
829
- throw new Error(
830
- `Garmin API error creating workout: ${createError ? JSON.stringify(createError) : "No data"}`,
831
- );
833
+ return {
834
+ data: null,
835
+ errors: [{ type: "pushWorkout", id: args.plannedWorkoutId, message: `Garmin API error creating workout: ${createError ? JSON.stringify(createError) : "No data"}` }],
836
+ };
832
837
  }
833
838
  if (!created.workoutId) {
834
- throw new Error("Garmin API did not return a workoutId after creation.");
839
+ return {
840
+ data: null,
841
+ errors: [{ type: "pushWorkout", id: args.plannedWorkoutId, message: "Garmin API did not return a workoutId after creation." }],
842
+ };
835
843
  }
836
844
  workoutId = created.workoutId;
837
845
  }
@@ -847,7 +855,7 @@ export const pushWorkout = action({
847
855
  },
848
856
  } as never);
849
857
 
850
- return { garminWorkoutId: workoutId };
858
+ return { data: { garminWorkoutId: workoutId }, errors: [] };
851
859
  },
852
860
  });
853
861
 
@@ -859,7 +867,10 @@ export const pushSchedule = action({
859
867
  plannedWorkoutId: v.string(),
860
868
  date: v.optional(v.string()),
861
869
  },
862
- handler: async (ctx, args): Promise<{ garminScheduleId: number }> => {
870
+ handler: async (ctx, args): Promise<{
871
+ data: { garminScheduleId: number } | null;
872
+ errors: Array<{ type: string; id: string; message: string }>;
873
+ }> => {
863
874
  const { connectionId, accessToken } = await ctx.runAction(
864
875
  internal.garmin.private.resolveConnectionAndAccessToken,
865
876
  { userId: args.userId, clientId: args.clientId, clientSecret: args.clientSecret },
@@ -901,9 +912,10 @@ export const pushSchedule = action({
901
912
  path: { workoutScheduleId: numericScheduleId },
902
913
  });
903
914
  if (updateError) {
904
- throw new Error(
905
- `Garmin API error updating schedule: ${JSON.stringify(updateError)}`,
906
- );
915
+ return {
916
+ data: null,
917
+ errors: [{ type: "pushSchedule", id: args.plannedWorkoutId, message: `Garmin API error updating schedule: ${JSON.stringify(updateError)}` }],
918
+ };
907
919
  }
908
920
  scheduleId = numericScheduleId;
909
921
  } else {
@@ -913,12 +925,16 @@ export const pushSchedule = action({
913
925
  body: { workoutId: Number(providerWorkoutId), date: scheduleDate },
914
926
  });
915
927
  if (scheduleError) {
916
- throw new Error(
917
- `Garmin API error creating schedule: ${JSON.stringify(scheduleError)}`,
918
- );
928
+ return {
929
+ data: null,
930
+ errors: [{ type: "pushSchedule", id: args.plannedWorkoutId, message: `Garmin API error creating schedule: ${JSON.stringify(scheduleError)}` }],
931
+ };
919
932
  }
920
933
  if (createdScheduleId == null) {
921
- throw new Error("Garmin API did not return a scheduleId after creation.");
934
+ return {
935
+ data: null,
936
+ errors: [{ type: "pushSchedule", id: args.plannedWorkoutId, message: "Garmin API did not return a scheduleId after creation." }],
937
+ };
922
938
  }
923
939
  scheduleId = createdScheduleId;
924
940
  }
@@ -934,7 +950,7 @@ export const pushSchedule = action({
934
950
  },
935
951
  } as never);
936
952
 
937
- return { garminScheduleId: scheduleId };
953
+ return { data: { garminScheduleId: scheduleId }, errors: [] };
938
954
  },
939
955
  });
940
956
 
@@ -947,7 +963,10 @@ export const deleteWorkout = action({
947
963
  clientSecret: v.string(),
948
964
  plannedWorkoutId: v.string(),
949
965
  },
950
- handler: async (ctx, args): Promise<null> => {
966
+ handler: async (ctx, args): Promise<{
967
+ data: null;
968
+ errors: Array<{ type: string; id: string; message: string }>;
969
+ }> => {
951
970
  const { connectionId, accessToken } = await ctx.runAction(
952
971
  internal.garmin.private.resolveConnectionAndAccessToken,
953
972
  { userId: args.userId, clientId: args.clientId, clientSecret: args.clientSecret },
@@ -973,9 +992,10 @@ export const deleteWorkout = action({
973
992
  path: { workoutId: Number(providerWorkoutId) },
974
993
  });
975
994
  if (deleteError) {
976
- throw new Error(
977
- `Garmin API error deleting workout: ${JSON.stringify(deleteError)}`,
978
- );
995
+ return {
996
+ data: null,
997
+ errors: [{ type: "deleteWorkout", id: args.plannedWorkoutId, message: `Garmin API error deleting workout: ${JSON.stringify(deleteError)}` }],
998
+ };
979
999
  }
980
1000
 
981
1001
  // Clear both provider IDs — deleting a workout on Garmin cascades to its schedules
@@ -990,7 +1010,7 @@ export const deleteWorkout = action({
990
1010
  },
991
1011
  } as never);
992
1012
 
993
- return null;
1013
+ return { data: null, errors: [] };
994
1014
  },
995
1015
  });
996
1016
 
@@ -1001,7 +1021,10 @@ export const deleteSchedule = action({
1001
1021
  clientSecret: v.string(),
1002
1022
  plannedWorkoutId: v.string(),
1003
1023
  },
1004
- handler: async (ctx, args): Promise<null> => {
1024
+ handler: async (ctx, args): Promise<{
1025
+ data: null;
1026
+ errors: Array<{ type: string; id: string; message: string }>;
1027
+ }> => {
1005
1028
  const { connectionId, accessToken } = await ctx.runAction(
1006
1029
  internal.garmin.private.resolveConnectionAndAccessToken,
1007
1030
  { userId: args.userId, clientId: args.clientId, clientSecret: args.clientSecret },
@@ -1027,9 +1050,10 @@ export const deleteSchedule = action({
1027
1050
  path: { workoutScheduleId: Number(providerScheduleId) },
1028
1051
  });
1029
1052
  if (deleteError) {
1030
- throw new Error(
1031
- `Garmin API error deleting schedule: ${JSON.stringify(deleteError)}`,
1032
- );
1053
+ return {
1054
+ data: null,
1055
+ errors: [{ type: "deleteSchedule", id: args.plannedWorkoutId, message: `Garmin API error deleting schedule: ${JSON.stringify(deleteError)}` }],
1056
+ };
1033
1057
  }
1034
1058
 
1035
1059
  // Clear only the schedule ID — the workout still exists on Garmin
@@ -1043,7 +1067,7 @@ export const deleteSchedule = action({
1043
1067
  },
1044
1068
  } as never);
1045
1069
 
1046
- return null;
1070
+ return { data: null, errors: [] };
1047
1071
  },
1048
1072
  });
1049
1073