@nativesquare/soma 0.7.3 → 0.8.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 (134) hide show
  1. package/dist/client/index.d.ts +83 -0
  2. package/dist/client/index.d.ts.map +1 -1
  3. package/dist/client/index.js +131 -0
  4. package/dist/client/index.js.map +1 -1
  5. package/dist/component/_generated/component.d.ts +159 -0
  6. package/dist/component/_generated/component.d.ts.map +1 -1
  7. package/dist/component/garmin.d.ts +190 -6
  8. package/dist/component/garmin.d.ts.map +1 -1
  9. package/dist/component/garmin.js +805 -25
  10. package/dist/component/garmin.js.map +1 -1
  11. package/dist/component/private.d.ts +18 -0
  12. package/dist/component/private.d.ts.map +1 -1
  13. package/dist/component/private.js +18 -0
  14. package/dist/component/private.js.map +1 -1
  15. package/dist/component/public.d.ts +88 -42
  16. package/dist/component/public.d.ts.map +1 -1
  17. package/dist/component/public.js +12 -2
  18. package/dist/component/public.js.map +1 -1
  19. package/dist/component/schema.d.ts +87 -32
  20. package/dist/component/schema.d.ts.map +1 -1
  21. package/dist/component/schema.js +2 -1
  22. package/dist/component/schema.js.map +1 -1
  23. package/dist/component/validators/connection.d.ts +1 -0
  24. package/dist/component/validators/connection.d.ts.map +1 -1
  25. package/dist/component/validators/connection.js +2 -0
  26. package/dist/component/validators/connection.js.map +1 -1
  27. package/dist/component/validators/daily.d.ts +40 -5
  28. package/dist/component/validators/daily.d.ts.map +1 -1
  29. package/dist/component/validators/daily.js +10 -1
  30. package/dist/component/validators/daily.js.map +1 -1
  31. package/dist/component/validators/enums.d.ts +1 -1
  32. package/dist/component/validators/plannedWorkout.d.ts +5 -1
  33. package/dist/component/validators/plannedWorkout.d.ts.map +1 -1
  34. package/dist/component/validators/plannedWorkout.js +4 -0
  35. package/dist/component/validators/plannedWorkout.js.map +1 -1
  36. package/dist/component/validators/sleep.d.ts +8 -8
  37. package/dist/garmin/activity.d.ts +7 -16
  38. package/dist/garmin/activity.d.ts.map +1 -1
  39. package/dist/garmin/activity.js +17 -23
  40. package/dist/garmin/activity.js.map +1 -1
  41. package/dist/garmin/bloodPressure.d.ts +28 -0
  42. package/dist/garmin/bloodPressure.d.ts.map +1 -0
  43. package/dist/garmin/bloodPressure.js +34 -0
  44. package/dist/garmin/bloodPressure.js.map +1 -0
  45. package/dist/garmin/body.js +1 -1
  46. package/dist/garmin/body.js.map +1 -1
  47. package/dist/garmin/client.d.ts +117 -17
  48. package/dist/garmin/client.d.ts.map +1 -1
  49. package/dist/garmin/client.js +337 -43
  50. package/dist/garmin/client.js.map +1 -1
  51. package/dist/garmin/daily.d.ts.map +1 -1
  52. package/dist/garmin/daily.js +3 -3
  53. package/dist/garmin/daily.js.map +1 -1
  54. package/dist/garmin/hrv.d.ts +30 -0
  55. package/dist/garmin/hrv.d.ts.map +1 -0
  56. package/dist/garmin/hrv.js +45 -0
  57. package/dist/garmin/hrv.js.map +1 -0
  58. package/dist/garmin/index.d.ts +16 -2
  59. package/dist/garmin/index.d.ts.map +1 -1
  60. package/dist/garmin/index.js +8 -1
  61. package/dist/garmin/index.js.map +1 -1
  62. package/dist/garmin/maps/activity-type.d.ts +1 -2
  63. package/dist/garmin/maps/activity-type.d.ts.map +1 -1
  64. package/dist/garmin/maps/activity-type.js +1 -0
  65. package/dist/garmin/maps/activity-type.js.map +1 -1
  66. package/dist/garmin/menstruation.d.ts +6 -4
  67. package/dist/garmin/menstruation.d.ts.map +1 -1
  68. package/dist/garmin/menstruation.js +12 -8
  69. package/dist/garmin/menstruation.js.map +1 -1
  70. package/dist/garmin/pulseOx.d.ts +24 -0
  71. package/dist/garmin/pulseOx.d.ts.map +1 -0
  72. package/dist/garmin/pulseOx.js +33 -0
  73. package/dist/garmin/pulseOx.js.map +1 -0
  74. package/dist/garmin/respiration.d.ts +29 -0
  75. package/dist/garmin/respiration.d.ts.map +1 -0
  76. package/dist/garmin/respiration.js +42 -0
  77. package/dist/garmin/respiration.js.map +1 -0
  78. package/dist/garmin/skinTemp.d.ts +27 -0
  79. package/dist/garmin/skinTemp.d.ts.map +1 -0
  80. package/dist/garmin/skinTemp.js +35 -0
  81. package/dist/garmin/skinTemp.js.map +1 -0
  82. package/dist/garmin/sleep.d.ts +4 -4
  83. package/dist/garmin/sleep.d.ts.map +1 -1
  84. package/dist/garmin/sleep.js +15 -9
  85. package/dist/garmin/sleep.js.map +1 -1
  86. package/dist/garmin/stressDetails.d.ts +30 -0
  87. package/dist/garmin/stressDetails.d.ts.map +1 -0
  88. package/dist/garmin/stressDetails.js +49 -0
  89. package/dist/garmin/stressDetails.js.map +1 -0
  90. package/dist/garmin/sync.d.ts +14 -0
  91. package/dist/garmin/sync.d.ts.map +1 -1
  92. package/dist/garmin/sync.js +287 -5
  93. package/dist/garmin/sync.js.map +1 -1
  94. package/dist/garmin/types.d.ts +77 -186
  95. package/dist/garmin/types.d.ts.map +1 -1
  96. package/dist/garmin/types.js +4 -2
  97. package/dist/garmin/types.js.map +1 -1
  98. package/dist/garmin/userMetrics.d.ts +23 -0
  99. package/dist/garmin/userMetrics.d.ts.map +1 -0
  100. package/dist/garmin/userMetrics.js +41 -0
  101. package/dist/garmin/userMetrics.js.map +1 -0
  102. package/dist/validators.d.ts +107 -28
  103. package/dist/validators.d.ts.map +1 -1
  104. package/package.json +133 -124
  105. package/src/client/index.ts +199 -0
  106. package/src/component/_generated/component.ts +161 -2
  107. package/src/component/garmin.ts +898 -26
  108. package/src/component/private.ts +21 -0
  109. package/src/component/public.ts +11 -2
  110. package/src/component/schema.ts +2 -1
  111. package/src/component/validators/connection.ts +2 -0
  112. package/src/component/validators/daily.ts +15 -0
  113. package/src/component/validators/plannedWorkout.ts +4 -0
  114. package/src/garmin/activity.test.ts +13 -21
  115. package/src/garmin/activity.ts +38 -45
  116. package/src/garmin/bloodPressure.ts +41 -0
  117. package/src/garmin/body.ts +1 -1
  118. package/src/garmin/client.ts +550 -71
  119. package/src/garmin/daily.ts +8 -4
  120. package/src/garmin/hrv.ts +57 -0
  121. package/src/garmin/index.ts +77 -7
  122. package/src/garmin/maps/activity-type.ts +2 -2
  123. package/src/garmin/menstruation.ts +14 -12
  124. package/src/garmin/pulseOx.ts +45 -0
  125. package/src/garmin/respiration.ts +55 -0
  126. package/src/garmin/skinTemp.ts +42 -0
  127. package/src/garmin/sleep.test.ts +5 -6
  128. package/src/garmin/sleep.ts +22 -16
  129. package/src/garmin/spec/wellness-api.json +1 -0
  130. package/src/garmin/stressDetails.ts +71 -0
  131. package/src/garmin/sync.ts +348 -5
  132. package/src/garmin/types.ts +88 -300
  133. package/src/garmin/userMetrics.ts +50 -0
  134. package/src/garmin/wellness-api.d.ts +5637 -0
@@ -11,6 +11,13 @@ import { transformDaily } from "./daily.js";
11
11
  import { transformSleep } from "./sleep.js";
12
12
  import { transformBody } from "./body.js";
13
13
  import { transformMenstruation } from "./menstruation.js";
14
+ import { transformBloodPressure } from "./bloodPressure.js";
15
+ import { transformSkinTemp } from "./skinTemp.js";
16
+ import { transformUserMetrics } from "./userMetrics.js";
17
+ import { transformHRV } from "./hrv.js";
18
+ import { transformStressDetails } from "./stressDetails.js";
19
+ import { transformPulseOx } from "./pulseOx.js";
20
+ import { transformRespiration } from "./respiration.js";
14
21
 
15
22
  // ─── Shared Types ────────────────────────────────────────────────────────────
16
23
 
@@ -34,6 +41,13 @@ export interface SyncAllResult {
34
41
  sleep: SyncResult;
35
42
  body: SyncResult;
36
43
  menstruation: SyncResult;
44
+ bloodPressures: SyncResult;
45
+ skinTemp: SyncResult;
46
+ userMetrics: SyncResult;
47
+ hrv: SyncResult;
48
+ stressDetails: SyncResult;
49
+ pulseOx: SyncResult;
50
+ respiration: SyncResult;
37
51
  }
38
52
 
39
53
  // ─── Sync All ────────────────────────────────────────────────────────────────
@@ -45,15 +59,48 @@ export interface SyncAllResult {
45
59
  * block the others.
46
60
  */
47
61
  export async function syncAll(opts: SyncOptions): Promise<SyncAllResult> {
48
- const [activities, dailies, sleep, body, menstruation] = await Promise.all([
62
+ const [
63
+ activities,
64
+ dailies,
65
+ sleep,
66
+ body,
67
+ menstruation,
68
+ bloodPressures,
69
+ skinTemp,
70
+ userMetrics,
71
+ hrv,
72
+ stressDetails,
73
+ pulseOx,
74
+ respiration,
75
+ ] = await Promise.all([
49
76
  syncActivities(opts),
50
77
  syncDailies(opts),
51
78
  syncSleep(opts),
52
79
  syncBody(opts),
53
80
  syncMenstruation(opts),
81
+ syncBloodPressures(opts),
82
+ syncSkinTemp(opts),
83
+ syncUserMetrics(opts),
84
+ syncHRV(opts),
85
+ syncStressDetails(opts),
86
+ syncPulseOx(opts),
87
+ syncRespiration(opts),
54
88
  ]);
55
89
 
56
- return { activities, dailies, sleep, body, menstruation };
90
+ return {
91
+ activities,
92
+ dailies,
93
+ sleep,
94
+ body,
95
+ menstruation,
96
+ bloodPressures,
97
+ skinTemp,
98
+ userMetrics,
99
+ hrv,
100
+ stressDetails,
101
+ pulseOx,
102
+ respiration,
103
+ };
57
104
  }
58
105
 
59
106
  // ─── Activities ──────────────────────────────────────────────────────────────
@@ -105,7 +152,7 @@ export async function syncDailies(opts: SyncOptions): Promise<SyncResult> {
105
152
  synced++;
106
153
  } catch (err) {
107
154
  errors.push({
108
- id: daily.summaryId ?? daily.calendarDate,
155
+ id: daily.summaryId ?? daily.calendarDate ?? "unknown",
109
156
  error: err instanceof Error ? err.message : String(err),
110
157
  });
111
158
  }
@@ -137,7 +184,7 @@ export async function syncSleep(opts: SyncOptions): Promise<SyncResult> {
137
184
  synced++;
138
185
  } catch (err) {
139
186
  errors.push({
140
- id: sleep.summaryId ?? sleep.calendarDate,
187
+ id: sleep.summaryId ?? sleep.calendarDate ?? "unknown",
141
188
  error: err instanceof Error ? err.message : String(err),
142
189
  });
143
190
  }
@@ -207,7 +254,303 @@ export async function syncMenstruation(
207
254
  synced++;
208
255
  } catch (err) {
209
256
  errors.push({
210
- id: record.summaryId ?? record.calendarDate,
257
+ id: record.summaryId ?? record.periodStartDate ?? "unknown",
258
+ error: err instanceof Error ? err.message : String(err),
259
+ });
260
+ }
261
+ }
262
+ } catch (err) {
263
+ errors.push({
264
+ id: "fetch",
265
+ error: err instanceof Error ? err.message : String(err),
266
+ });
267
+ }
268
+
269
+ return { synced, errors };
270
+ }
271
+
272
+ // ─── Blood Pressures ────────────────────────────────────────────────────────
273
+
274
+ export async function syncBloodPressures(
275
+ opts: SyncOptions,
276
+ ): Promise<SyncResult> {
277
+ const { client, soma, ctx, connectionId, userId, timeRange } = opts;
278
+ let synced = 0;
279
+ const errors: SyncResult["errors"] = [];
280
+
281
+ try {
282
+ const records = await client.getBloodPressures(timeRange);
283
+
284
+ for (const record of records) {
285
+ try {
286
+ const data = transformBloodPressure(record);
287
+ await soma.ingestBody(ctx, { connectionId, userId, ...data });
288
+ synced++;
289
+ } catch (err) {
290
+ errors.push({
291
+ id: record.summaryId ?? String(record.measurementTimeInSeconds),
292
+ error: err instanceof Error ? err.message : String(err),
293
+ });
294
+ }
295
+ }
296
+ } catch (err) {
297
+ errors.push({
298
+ id: "fetch",
299
+ error: err instanceof Error ? err.message : String(err),
300
+ });
301
+ }
302
+
303
+ return { synced, errors };
304
+ }
305
+
306
+ // ─── Skin Temperature ───────────────────────────────────────────────────────
307
+
308
+ export async function syncSkinTemp(opts: SyncOptions): Promise<SyncResult> {
309
+ const { client, soma, ctx, connectionId, userId, timeRange } = opts;
310
+ let synced = 0;
311
+ const errors: SyncResult["errors"] = [];
312
+
313
+ try {
314
+ const records = await client.getSkinTemperature(timeRange);
315
+
316
+ for (const record of records) {
317
+ try {
318
+ const data = transformSkinTemp(record);
319
+ await soma.ingestBody(ctx, { connectionId, userId, ...data });
320
+ synced++;
321
+ } catch (err) {
322
+ errors.push({
323
+ id: record.summaryId ?? record.calendarDate ?? "unknown",
324
+ error: err instanceof Error ? err.message : String(err),
325
+ });
326
+ }
327
+ }
328
+ } catch (err) {
329
+ errors.push({
330
+ id: "fetch",
331
+ error: err instanceof Error ? err.message : String(err),
332
+ });
333
+ }
334
+
335
+ return { synced, errors };
336
+ }
337
+
338
+ // ─── User Metrics ───────────────────────────────────────────────────────────
339
+
340
+ export async function syncUserMetrics(opts: SyncOptions): Promise<SyncResult> {
341
+ const { client, soma, ctx, connectionId, userId, timeRange } = opts;
342
+ let synced = 0;
343
+ const errors: SyncResult["errors"] = [];
344
+
345
+ try {
346
+ const records = await client.getUserMetrics(timeRange);
347
+
348
+ for (const record of records) {
349
+ try {
350
+ const data = transformUserMetrics(record);
351
+ await soma.ingestBody(ctx, { connectionId, userId, ...data });
352
+ synced++;
353
+ } catch (err) {
354
+ errors.push({
355
+ id: record.summaryId ?? record.calendarDate ?? "unknown",
356
+ error: err instanceof Error ? err.message : String(err),
357
+ });
358
+ }
359
+ }
360
+ } catch (err) {
361
+ errors.push({
362
+ id: "fetch",
363
+ error: err instanceof Error ? err.message : String(err),
364
+ });
365
+ }
366
+
367
+ return { synced, errors };
368
+ }
369
+
370
+ // ─── HRV (enriches Daily) ───────────────────────────────────────────────────
371
+
372
+ export async function syncHRV(opts: SyncOptions): Promise<SyncResult> {
373
+ const { client, soma, ctx, connectionId, userId, timeRange } = opts;
374
+ let synced = 0;
375
+ const errors: SyncResult["errors"] = [];
376
+
377
+ try {
378
+ const records = await client.getHRV(timeRange);
379
+
380
+ for (const record of records) {
381
+ try {
382
+ const data = transformHRV(record);
383
+ if (data.heart_rate_data) {
384
+ await soma.ingestDaily(ctx, {
385
+ connectionId,
386
+ userId,
387
+ metadata: {
388
+ start_time: new Date(
389
+ (record.startTimeInSeconds ?? 0) * 1000,
390
+ ).toISOString(),
391
+ end_time: new Date(
392
+ ((record.startTimeInSeconds ?? 0) +
393
+ (record.durationInSeconds ?? 86400)) *
394
+ 1000,
395
+ ).toISOString(),
396
+ upload_type: 1,
397
+ },
398
+ heart_rate_data: data.heart_rate_data,
399
+ });
400
+ synced++;
401
+ }
402
+ } catch (err) {
403
+ errors.push({
404
+ id: record.summaryId ?? record.calendarDate ?? "unknown",
405
+ error: err instanceof Error ? err.message : String(err),
406
+ });
407
+ }
408
+ }
409
+ } catch (err) {
410
+ errors.push({
411
+ id: "fetch",
412
+ error: err instanceof Error ? err.message : String(err),
413
+ });
414
+ }
415
+
416
+ return { synced, errors };
417
+ }
418
+
419
+ // ─── Stress Details (enriches Daily) ────────────────────────────────────────
420
+
421
+ export async function syncStressDetails(
422
+ opts: SyncOptions,
423
+ ): Promise<SyncResult> {
424
+ const { client, soma, ctx, connectionId, userId, timeRange } = opts;
425
+ let synced = 0;
426
+ const errors: SyncResult["errors"] = [];
427
+
428
+ try {
429
+ const records = await client.getStressDetails(timeRange);
430
+
431
+ for (const record of records) {
432
+ try {
433
+ const data = transformStressDetails(record);
434
+ if (data.stress_data) {
435
+ await soma.ingestDaily(ctx, {
436
+ connectionId,
437
+ userId,
438
+ metadata: {
439
+ start_time: new Date(
440
+ (record.startTimeInSeconds ?? 0) * 1000,
441
+ ).toISOString(),
442
+ end_time: new Date(
443
+ ((record.startTimeInSeconds ?? 0) +
444
+ (record.durationInSeconds ?? 86400)) *
445
+ 1000,
446
+ ).toISOString(),
447
+ upload_type: 1,
448
+ },
449
+ stress_data: data.stress_data,
450
+ });
451
+ synced++;
452
+ }
453
+ } catch (err) {
454
+ errors.push({
455
+ id: record.summaryId ?? record.calendarDate ?? "unknown",
456
+ error: err instanceof Error ? err.message : String(err),
457
+ });
458
+ }
459
+ }
460
+ } catch (err) {
461
+ errors.push({
462
+ id: "fetch",
463
+ error: err instanceof Error ? err.message : String(err),
464
+ });
465
+ }
466
+
467
+ return { synced, errors };
468
+ }
469
+
470
+ // ─── Pulse Ox (enriches Daily) ──────────────────────────────────────────────
471
+
472
+ export async function syncPulseOx(opts: SyncOptions): Promise<SyncResult> {
473
+ const { client, soma, ctx, connectionId, userId, timeRange } = opts;
474
+ let synced = 0;
475
+ const errors: SyncResult["errors"] = [];
476
+
477
+ try {
478
+ const records = await client.getPulseOx(timeRange);
479
+
480
+ for (const record of records) {
481
+ try {
482
+ const data = transformPulseOx(record);
483
+ if (data.oxygen_data) {
484
+ await soma.ingestDaily(ctx, {
485
+ connectionId,
486
+ userId,
487
+ metadata: {
488
+ start_time: new Date(
489
+ (record.startTimeInSeconds ?? 0) * 1000,
490
+ ).toISOString(),
491
+ end_time: new Date(
492
+ ((record.startTimeInSeconds ?? 0) +
493
+ (record.durationInSeconds ?? 86400)) *
494
+ 1000,
495
+ ).toISOString(),
496
+ upload_type: 1,
497
+ },
498
+ oxygen_data: data.oxygen_data,
499
+ });
500
+ synced++;
501
+ }
502
+ } catch (err) {
503
+ errors.push({
504
+ id: record.summaryId ?? record.calendarDate ?? "unknown",
505
+ error: err instanceof Error ? err.message : String(err),
506
+ });
507
+ }
508
+ }
509
+ } catch (err) {
510
+ errors.push({
511
+ id: "fetch",
512
+ error: err instanceof Error ? err.message : String(err),
513
+ });
514
+ }
515
+
516
+ return { synced, errors };
517
+ }
518
+
519
+ // ─── Respiration (enriches Daily) ───────────────────────────────────────────
520
+
521
+ export async function syncRespiration(opts: SyncOptions): Promise<SyncResult> {
522
+ const { client, soma, ctx, connectionId, userId, timeRange } = opts;
523
+ let synced = 0;
524
+ const errors: SyncResult["errors"] = [];
525
+
526
+ try {
527
+ const records = await client.getRespiration(timeRange);
528
+
529
+ for (const record of records) {
530
+ try {
531
+ const data = transformRespiration(record);
532
+ if (data.respiration_data) {
533
+ await soma.ingestDaily(ctx, {
534
+ connectionId,
535
+ userId,
536
+ metadata: {
537
+ start_time: new Date(
538
+ (record.startTimeInSeconds ?? 0) * 1000,
539
+ ).toISOString(),
540
+ end_time: new Date(
541
+ ((record.startTimeInSeconds ?? 0) +
542
+ (record.durationInSeconds ?? 86400)) *
543
+ 1000,
544
+ ).toISOString(),
545
+ upload_type: 1,
546
+ },
547
+ respiration_data: data.respiration_data,
548
+ });
549
+ synced++;
550
+ }
551
+ } catch (err) {
552
+ errors.push({
553
+ id: record.summaryId ?? "unknown",
211
554
  error: err instanceof Error ? err.message : String(err),
212
555
  });
213
556
  }