@nativesquare/soma 0.3.0 → 0.5.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 (101) hide show
  1. package/dist/client/index.d.ts +283 -0
  2. package/dist/client/index.d.ts.map +1 -1
  3. package/dist/client/index.js +328 -0
  4. package/dist/client/index.js.map +1 -1
  5. package/dist/component/_generated/api.d.ts +2 -0
  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 +77 -0
  9. package/dist/component/_generated/component.d.ts.map +1 -1
  10. package/dist/component/garmin.d.ts +164 -0
  11. package/dist/component/garmin.d.ts.map +1 -0
  12. package/dist/component/garmin.js +609 -0
  13. package/dist/component/garmin.js.map +1 -0
  14. package/dist/component/public.d.ts +761 -761
  15. package/dist/component/schema.d.ts +405 -388
  16. package/dist/component/schema.d.ts.map +1 -1
  17. package/dist/component/schema.js +14 -2
  18. package/dist/component/schema.js.map +1 -1
  19. package/dist/component/strava.d.ts +5 -4
  20. package/dist/component/strava.d.ts.map +1 -1
  21. package/dist/component/strava.js +18 -1
  22. package/dist/component/strava.js.map +1 -1
  23. package/dist/component/validators/activity.d.ts +42 -42
  24. package/dist/component/validators/body.d.ts +47 -47
  25. package/dist/component/validators/daily.d.ts +17 -17
  26. package/dist/component/validators/plannedWorkout.d.ts +5 -5
  27. package/dist/component/validators/samples.d.ts +2 -2
  28. package/dist/component/validators/shared.d.ts +17 -17
  29. package/dist/component/validators/sleep.d.ts +17 -17
  30. package/dist/garmin/activity.d.ts +101 -0
  31. package/dist/garmin/activity.d.ts.map +1 -0
  32. package/dist/garmin/activity.js +207 -0
  33. package/dist/garmin/activity.js.map +1 -0
  34. package/dist/garmin/auth.d.ts +65 -0
  35. package/dist/garmin/auth.d.ts.map +1 -0
  36. package/dist/garmin/auth.js +155 -0
  37. package/dist/garmin/auth.js.map +1 -0
  38. package/dist/garmin/body.d.ts +26 -0
  39. package/dist/garmin/body.d.ts.map +1 -0
  40. package/dist/garmin/body.js +44 -0
  41. package/dist/garmin/body.js.map +1 -0
  42. package/dist/garmin/client.d.ts +99 -0
  43. package/dist/garmin/client.d.ts.map +1 -0
  44. package/dist/garmin/client.js +153 -0
  45. package/dist/garmin/client.js.map +1 -0
  46. package/dist/garmin/daily.d.ts +74 -0
  47. package/dist/garmin/daily.d.ts.map +1 -0
  48. package/dist/garmin/daily.js +143 -0
  49. package/dist/garmin/daily.js.map +1 -0
  50. package/dist/garmin/index.d.ts +20 -0
  51. package/dist/garmin/index.d.ts.map +1 -0
  52. package/dist/garmin/index.js +21 -0
  53. package/dist/garmin/index.js.map +1 -0
  54. package/dist/garmin/maps/activity-type.d.ts +7 -0
  55. package/dist/garmin/maps/activity-type.d.ts.map +1 -0
  56. package/dist/garmin/maps/activity-type.js +98 -0
  57. package/dist/garmin/maps/activity-type.js.map +1 -0
  58. package/dist/garmin/maps/sleep-level.d.ts +6 -0
  59. package/dist/garmin/maps/sleep-level.d.ts.map +1 -0
  60. package/dist/garmin/maps/sleep-level.js +21 -0
  61. package/dist/garmin/maps/sleep-level.js.map +1 -0
  62. package/dist/garmin/menstruation.d.ts +23 -0
  63. package/dist/garmin/menstruation.d.ts.map +1 -0
  64. package/dist/garmin/menstruation.js +34 -0
  65. package/dist/garmin/menstruation.js.map +1 -0
  66. package/dist/garmin/sleep.d.ts +62 -0
  67. package/dist/garmin/sleep.d.ts.map +1 -0
  68. package/dist/garmin/sleep.js +125 -0
  69. package/dist/garmin/sleep.js.map +1 -0
  70. package/dist/garmin/sync.d.ts +39 -0
  71. package/dist/garmin/sync.d.ts.map +1 -0
  72. package/dist/garmin/sync.js +175 -0
  73. package/dist/garmin/sync.js.map +1 -0
  74. package/dist/garmin/types.d.ts +212 -0
  75. package/dist/garmin/types.d.ts.map +1 -0
  76. package/dist/garmin/types.js +8 -0
  77. package/dist/garmin/types.js.map +1 -0
  78. package/dist/validators.d.ts +331 -331
  79. package/package.json +5 -1
  80. package/src/client/index.ts +446 -1
  81. package/src/component/_generated/api.ts +2 -0
  82. package/src/component/_generated/component.ts +89 -0
  83. package/src/component/garmin.ts +711 -0
  84. package/src/component/schema.ts +15 -2
  85. package/src/component/strava.ts +23 -1
  86. package/src/garmin/activity.test.ts +178 -0
  87. package/src/garmin/activity.ts +272 -0
  88. package/src/garmin/auth.test.ts +128 -0
  89. package/src/garmin/auth.ts +249 -0
  90. package/src/garmin/body.ts +59 -0
  91. package/src/garmin/client.ts +254 -0
  92. package/src/garmin/daily.ts +211 -0
  93. package/src/garmin/index.ts +76 -0
  94. package/src/garmin/maps/activity-type.test.ts +78 -0
  95. package/src/garmin/maps/activity-type.ts +116 -0
  96. package/src/garmin/maps/sleep-level.ts +22 -0
  97. package/src/garmin/menstruation.ts +42 -0
  98. package/src/garmin/sleep.test.ts +110 -0
  99. package/src/garmin/sleep.ts +170 -0
  100. package/src/garmin/sync.ts +223 -0
  101. package/src/garmin/types.ts +338 -0
@@ -0,0 +1,143 @@
1
+ // ─── Daily Transformer ───────────────────────────────────────────────────────
2
+ // Transforms a Garmin daily wellness summary into the Soma Daily schema shape.
3
+ /**
4
+ * Transform a Garmin daily summary into a Soma Daily document shape.
5
+ *
6
+ * @param daily - The Garmin daily summary from the Health API
7
+ * @returns Soma Daily fields (without connectionId/userId)
8
+ */
9
+ export function transformDaily(daily) {
10
+ const startMs = daily.startTimeInSeconds * 1000;
11
+ const endMs = startMs + daily.durationInSeconds * 1000;
12
+ return {
13
+ metadata: {
14
+ start_time: new Date(startMs).toISOString(),
15
+ end_time: new Date(endMs).toISOString(),
16
+ upload_type: 1, // Automatic
17
+ },
18
+ active_durations_data: buildActiveDurationsData(daily),
19
+ calories_data: buildCaloriesData(daily),
20
+ distance_data: buildDistanceData(daily),
21
+ heart_rate_data: buildHeartRateData(daily),
22
+ oxygen_data: buildOxygenData(daily),
23
+ stress_data: buildStressData(daily),
24
+ };
25
+ }
26
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
27
+ function buildActiveDurationsData(daily) {
28
+ if (daily.activeTimeInSeconds == null &&
29
+ daily.moderateIntensityDurationInSeconds == null &&
30
+ daily.vigorousIntensityDurationInSeconds == null) {
31
+ return undefined;
32
+ }
33
+ return {
34
+ activity_seconds: daily.activeTimeInSeconds,
35
+ moderate_intensity_seconds: daily.moderateIntensityDurationInSeconds,
36
+ vigorous_intensity_seconds: daily.vigorousIntensityDurationInSeconds,
37
+ };
38
+ }
39
+ function buildCaloriesData(daily) {
40
+ if (daily.activeKilocalories == null && daily.bmrKilocalories == null) {
41
+ return undefined;
42
+ }
43
+ const total = (daily.activeKilocalories ?? 0) + (daily.bmrKilocalories ?? 0);
44
+ return {
45
+ net_activity_calories: daily.activeKilocalories,
46
+ BMR_calories: daily.bmrKilocalories,
47
+ total_burned_calories: total || undefined,
48
+ };
49
+ }
50
+ function buildDistanceData(daily) {
51
+ if (daily.distanceInMeters == null &&
52
+ daily.steps == null &&
53
+ daily.floorsClimbed == null) {
54
+ return undefined;
55
+ }
56
+ return {
57
+ distance_meters: daily.distanceInMeters,
58
+ steps: daily.steps,
59
+ floors_climbed: daily.floorsClimbed,
60
+ };
61
+ }
62
+ function buildHeartRateData(daily) {
63
+ const hasSummary = daily.averageHeartRateInBeatsPerMinute != null ||
64
+ daily.maxHeartRateInBeatsPerMinute != null ||
65
+ daily.restingHeartRateInBeatsPerMinute != null;
66
+ const hasSamples = daily.timeOffsetHeartRateSamples != null &&
67
+ Object.keys(daily.timeOffsetHeartRateSamples).length > 0;
68
+ if (!hasSummary && !hasSamples)
69
+ return undefined;
70
+ const hrSamples = hasSamples
71
+ ? buildTimeOffsetSamples(daily.startTimeInSeconds, daily.timeOffsetHeartRateSamples, (bpm) => ({ bpm }))
72
+ : undefined;
73
+ return {
74
+ summary: hasSummary
75
+ ? {
76
+ avg_hr_bpm: daily.averageHeartRateInBeatsPerMinute,
77
+ max_hr_bpm: daily.maxHeartRateInBeatsPerMinute,
78
+ min_hr_bpm: daily.minHeartRateInBeatsPerMinute,
79
+ resting_hr_bpm: daily.restingHeartRateInBeatsPerMinute,
80
+ }
81
+ : undefined,
82
+ detailed: hrSamples && hrSamples.length > 0
83
+ ? { hr_samples: hrSamples }
84
+ : undefined,
85
+ };
86
+ }
87
+ function buildOxygenData(daily) {
88
+ if (daily.averageSpo2Value == null && daily.timeOffsetSpo2Values == null) {
89
+ return undefined;
90
+ }
91
+ const samples = daily.timeOffsetSpo2Values != null
92
+ ? buildTimeOffsetSamples(daily.startTimeInSeconds, daily.timeOffsetSpo2Values, (pct) => ({ percentage: pct }))
93
+ : undefined;
94
+ return {
95
+ avg_saturation_percentage: daily.averageSpo2Value,
96
+ saturation_samples: samples && samples.length > 0 ? samples : undefined,
97
+ };
98
+ }
99
+ function buildStressData(daily) {
100
+ const hasStress = daily.averageStressLevel != null ||
101
+ daily.maxStressLevel != null ||
102
+ daily.stressDurationInSeconds != null;
103
+ const hasStressSamples = daily.timeOffsetStressLevelValues != null &&
104
+ Object.keys(daily.timeOffsetStressLevelValues).length > 0;
105
+ const hasBodyBatterySamples = daily.timeOffsetBodyBatteryValues != null &&
106
+ Object.keys(daily.timeOffsetBodyBatteryValues).length > 0;
107
+ if (!hasStress && !hasStressSamples && !hasBodyBatterySamples) {
108
+ return undefined;
109
+ }
110
+ const stressSamples = hasStressSamples
111
+ ? buildTimeOffsetSamples(daily.startTimeInSeconds, daily.timeOffsetStressLevelValues, (level) => ({ level }))
112
+ : undefined;
113
+ const bodyBatterySamples = hasBodyBatterySamples
114
+ ? buildTimeOffsetSamples(daily.startTimeInSeconds, daily.timeOffsetBodyBatteryValues, (level) => ({ level }))
115
+ : undefined;
116
+ return {
117
+ avg_stress_level: daily.averageStressLevel,
118
+ max_stress_level: daily.maxStressLevel,
119
+ stress_duration_seconds: daily.stressDurationInSeconds,
120
+ rest_stress_duration_seconds: daily.restStressDurationInSeconds,
121
+ activity_stress_duration_seconds: daily.activityStressDurationInSeconds,
122
+ low_stress_duration_seconds: daily.lowStressDurationInSeconds,
123
+ medium_stress_duration_seconds: daily.mediumStressDurationInSeconds,
124
+ high_stress_duration_seconds: daily.highStressDurationInSeconds,
125
+ samples: stressSamples && stressSamples.length > 0 ? stressSamples : undefined,
126
+ body_battery_samples: bodyBatterySamples && bodyBatterySamples.length > 0
127
+ ? bodyBatterySamples
128
+ : undefined,
129
+ };
130
+ }
131
+ /**
132
+ * Convert Garmin offset-keyed time-series data into timestamped samples.
133
+ *
134
+ * Garmin sends time-series as `{ [offsetSeconds]: value }` maps.
135
+ * This converts to `{ timestamp: ISO-8601, ...fields }[]`.
136
+ */
137
+ function buildTimeOffsetSamples(startTimeInSeconds, offsets, mapValue) {
138
+ return Object.entries(offsets).map(([offset, value]) => ({
139
+ timestamp: new Date((startTimeInSeconds + parseInt(offset, 10)) * 1000).toISOString(),
140
+ ...mapValue(value),
141
+ }));
142
+ }
143
+ //# sourceMappingURL=daily.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"daily.js","sourceRoot":"","sources":["../../src/garmin/daily.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ export { transformActivity } from "./activity.js";
2
+ export type { ActivityData } from "./activity.js";
3
+ export { transformDaily } from "./daily.js";
4
+ export type { DailyData } from "./daily.js";
5
+ export { transformSleep } from "./sleep.js";
6
+ export type { SleepData } from "./sleep.js";
7
+ export { transformBody } from "./body.js";
8
+ export type { BodyData } from "./body.js";
9
+ export { transformMenstruation } from "./menstruation.js";
10
+ export type { MenstruationData } from "./menstruation.js";
11
+ export { mapActivityType } from "./maps/activity-type.js";
12
+ export { mapSleepLevel } from "./maps/sleep-level.js";
13
+ export { GarminClient, GarminApiError } from "./client.js";
14
+ export type { GarminClientOptions, TimeRangeParams } from "./client.js";
15
+ export { getRequestToken, getAccessToken, buildOAuthSignature, buildOAuthHeader, percentEncode, generateNonce, getTimestamp, } from "./auth.js";
16
+ export type { GetRequestTokenOptions, GetAccessTokenOptions, } from "./auth.js";
17
+ export { syncAll, syncActivities, syncDailies, syncSleep, syncBody, syncMenstruation, } from "./sync.js";
18
+ export type { SyncOptions, SyncResult, SyncAllResult, } from "./sync.js";
19
+ export type { GarminActivity, GarminActivityLap, GarminActivitySample, GarminDailySummary, GarminSleep, GarminSleepLevel, GarminBodyComposition, GarminMenstrualCycleData, GarminUserProfile, GarminActivityType, GarminOAuthRequestTokenResponse, GarminOAuthAccessTokenResponse, GarminWebhookPayload, } from "./types.js";
20
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/garmin/index.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAClD,YAAY,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAElD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAC5C,YAAY,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAE5C,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAC1C,YAAY,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AAE1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAC1D,YAAY,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAGtD,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC3D,YAAY,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAGxE,OAAO,EACL,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,YAAY,GACb,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,sBAAsB,EACtB,qBAAqB,GACtB,MAAM,WAAW,CAAC;AAGnB,OAAO,EACL,OAAO,EACP,cAAc,EACd,WAAW,EACX,SAAS,EACT,QAAQ,EACR,gBAAgB,GACjB,MAAM,WAAW,CAAC;AACnB,YAAY,EACV,WAAW,EACX,UAAU,EACV,aAAa,GACd,MAAM,WAAW,CAAC;AAGnB,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,oBAAoB,EACpB,kBAAkB,EAClB,WAAW,EACX,gBAAgB,EAChB,qBAAqB,EACrB,wBAAwB,EACxB,iBAAiB,EACjB,kBAAkB,EAClB,+BAA+B,EAC/B,8BAA8B,EAC9B,oBAAoB,GACrB,MAAM,YAAY,CAAC"}
@@ -0,0 +1,21 @@
1
+ // ─── @nativesquare/soma/garmin ───────────────────────────────────────────────
2
+ // Garmin Health API → Soma schema transformers, API client, OAuth helpers, and sync.
3
+ //
4
+ // Uses the Web Crypto API for OAuth 1.0a HMAC-SHA1 signing.
5
+ // Compatible with both the Convex V8 runtime and Node.js environments.
6
+ // ── Transformers ─────────────────────────────────────────────────────────────
7
+ export { transformActivity } from "./activity.js";
8
+ export { transformDaily } from "./daily.js";
9
+ export { transformSleep } from "./sleep.js";
10
+ export { transformBody } from "./body.js";
11
+ export { transformMenstruation } from "./menstruation.js";
12
+ // ── Enum Maps ────────────────────────────────────────────────────────────────
13
+ export { mapActivityType } from "./maps/activity-type.js";
14
+ export { mapSleepLevel } from "./maps/sleep-level.js";
15
+ // ── API Client ───────────────────────────────────────────────────────────────
16
+ export { GarminClient, GarminApiError } from "./client.js";
17
+ // ── OAuth Helpers ────────────────────────────────────────────────────────────
18
+ export { getRequestToken, getAccessToken, buildOAuthSignature, buildOAuthHeader, percentEncode, generateNonce, getTimestamp, } from "./auth.js";
19
+ // ── Sync Helpers ─────────────────────────────────────────────────────────────
20
+ export { syncAll, syncActivities, syncDailies, syncSleep, syncBody, syncMenstruation, } from "./sync.js";
21
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/garmin/index.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,qFAAqF;AACrF,EAAE;AACF,4DAA4D;AAC5D,uEAAuE;AAEvE,gFAAgF;AAChF,OAAO,EAAE,iBAAiB,EAAE,MAAM,eAAe,CAAC;AAGlD,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAG5C,OAAO,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAG5C,OAAO,EAAE,aAAa,EAAE,MAAM,WAAW,CAAC;AAG1C,OAAO,EAAE,qBAAqB,EAAE,MAAM,mBAAmB,CAAC;AAG1D,gFAAgF;AAChF,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAEtD,gFAAgF;AAChF,OAAO,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAG3D,gFAAgF;AAChF,OAAO,EACL,eAAe,EACf,cAAc,EACd,mBAAmB,EACnB,gBAAgB,EAChB,aAAa,EACb,aAAa,EACb,YAAY,GACb,MAAM,WAAW,CAAC;AAMnB,gFAAgF;AAChF,OAAO,EACL,OAAO,EACP,cAAc,EACd,WAAW,EACX,SAAS,EACT,QAAQ,EACR,gBAAgB,GACjB,MAAM,WAAW,CAAC"}
@@ -0,0 +1,7 @@
1
+ import type { GarminActivityType } from "../types.js";
2
+ /**
3
+ * Map a Garmin activity type string to the Terra ActivityType enum.
4
+ * Returns Terra "Other" (108) for unknown types.
5
+ */
6
+ export declare function mapActivityType(activityType: GarminActivityType): number;
7
+ //# sourceMappingURL=activity-type.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-type.d.ts","sourceRoot":"","sources":["../../../src/garmin/maps/activity-type.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,aAAa,CAAC;AAsGtD;;;GAGG;AACH,wBAAgB,eAAe,CAAC,YAAY,EAAE,kBAAkB,GAAG,MAAM,CAExE"}
@@ -0,0 +1,98 @@
1
+ // ─── Garmin ActivityType → Terra ActivityType ─────────────────────────────────
2
+ // Maps Garmin activity type strings to Terra's ActivityType numeric enum
3
+ // used by the Soma schema.
4
+ //
5
+ // Garmin values: Garmin Health API activity type strings
6
+ // Terra values: https://docs.tryterra.co/reference/health-and-fitness-api/data-models#activitytype
7
+ const activityTypeMap = {
8
+ // ── Running ─────────────────────────────────────────────────────────────
9
+ // Terra Running = 8
10
+ RUNNING: 8,
11
+ INDOOR_RUNNING: 8,
12
+ TRAIL_RUNNING: 8,
13
+ TREADMILL_RUNNING: 8,
14
+ // ── Cycling ─────────────────────────────────────────────────────────────
15
+ // Terra Biking = 1
16
+ CYCLING: 1,
17
+ INDOOR_CYCLING: 1,
18
+ MOUNTAIN_BIKING: 1,
19
+ GRAVEL_CYCLING: 1,
20
+ VIRTUAL_RIDE: 1,
21
+ // ── Walking ─────────────────────────────────────────────────────────────
22
+ // Terra Walking = 7
23
+ WALKING: 7,
24
+ // ── Hiking ──────────────────────────────────────────────────────────────
25
+ // Terra Hiking = 35
26
+ HIKING: 35,
27
+ // ── Swimming ────────────────────────────────────────────────────────────
28
+ // Terra Swimming = 82
29
+ SWIMMING: 82,
30
+ OPEN_WATER_SWIMMING: 82,
31
+ LAP_SWIMMING: 82,
32
+ POOL_SWIMMING: 82,
33
+ // ── Gym / Fitness ───────────────────────────────────────────────────────
34
+ STRENGTH_TRAINING: 80, // Terra Strength Training
35
+ YOGA: 100, // Terra Yoga
36
+ PILATES: 49, // Terra Pilates
37
+ CARDIO: 108, // Terra Other
38
+ ELLIPTICAL: 25, // Terra Elliptical
39
+ STAIR_CLIMBING: 78, // Terra Stair Climbing Machine
40
+ CROSSFIT: 113, // Terra Crossfit
41
+ HIIT: 114, // Terra HIIT
42
+ FITNESS_EQUIPMENT: 108, // Terra Other
43
+ BREATHWORK: 108, // Terra Other
44
+ // ── Snow Sports ─────────────────────────────────────────────────────────
45
+ CROSS_COUNTRY_SKIING: 67, // Terra Cross Country Skiing
46
+ ALPINE_SKIING: 66, // Terra Alpine Skiing
47
+ SNOWBOARDING: 73, // Terra Snowboarding
48
+ SNOWSHOEING: 74, // Terra Snowshoeing
49
+ // ── Water Sports ────────────────────────────────────────────────────────
50
+ ROWING: 53, // Terra Rowing
51
+ INDOOR_ROWING: 53, // Terra Rowing
52
+ KAYAKING: 40, // Terra Kayaking
53
+ CANOEING: 22, // Terra Canoeing
54
+ SAILING: 59, // Terra Sailing
55
+ SURFING: 81, // Terra Surfing
56
+ KITESURFING: 41, // Terra Kitesurfing
57
+ WINDSURFING: 99, // Terra Windsurfing
58
+ PADDLEBOARDING: 129, // Terra Paddling
59
+ // ── Skating ─────────────────────────────────────────────────────────────
60
+ SKATING: 62, // Terra Skating
61
+ INLINE_SKATING: 62, // Terra Skating
62
+ // ── Racket Sports ───────────────────────────────────────────────────────
63
+ TENNIS: 87, // Terra Tennis
64
+ TABLE_TENNIS: 85, // Terra Table Tennis
65
+ BADMINTON: 10, // Terra Badminton
66
+ RACQUETBALL: 51, // Terra Racquetball
67
+ SQUASH: 76, // Terra Squash
68
+ // ── Climbing ────────────────────────────────────────────────────────────
69
+ ROCK_CLIMBING: 52, // Terra Rock Climbing
70
+ BOULDERING: 52, // Terra Rock Climbing
71
+ // ── Team Sports ─────────────────────────────────────────────────────────
72
+ SOCCER: 29, // Terra English Football
73
+ BASKETBALL: 11, // Terra Basketball
74
+ VOLLEYBALL: 94, // Terra Volleyball
75
+ CRICKET: 23, // Terra Cricket
76
+ RUGBY: 57, // Terra Rugby
77
+ // ── Combat Sports ───────────────────────────────────────────────────────
78
+ BOXING: 16, // Terra Boxing
79
+ MARTIAL_ARTS: 44, // Terra Martial Arts
80
+ // ── Golf ────────────────────────────────────────────────────────────────
81
+ GOLF: 32, // Terra Golf
82
+ // ── Accessibility ───────────────────────────────────────────────────────
83
+ HANDCYCLING: 14, // Terra Handbiking
84
+ WHEELCHAIR_PUSH_WALKING: 98, // Terra Wheelchair
85
+ WHEELCHAIR_PUSH_RUNNING: 98, // Terra Wheelchair
86
+ // ── Other ───────────────────────────────────────────────────────────────
87
+ OTHER: 108, // Terra Other
88
+ MULTI_SPORT: 108, // Terra Other
89
+ FLOOR_CLIMBING: 78, // Terra Stair Climbing Machine
90
+ };
91
+ /**
92
+ * Map a Garmin activity type string to the Terra ActivityType enum.
93
+ * Returns Terra "Other" (108) for unknown types.
94
+ */
95
+ export function mapActivityType(activityType) {
96
+ return activityTypeMap[activityType] ?? 108;
97
+ }
98
+ //# sourceMappingURL=activity-type.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"activity-type.js","sourceRoot":"","sources":["../../../src/garmin/maps/activity-type.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ /**
2
+ * Map a Garmin sleep stage name to the Terra SleepLevel enum.
3
+ * Returns 0 (Unknown) for unrecognized stages.
4
+ */
5
+ export declare function mapSleepLevel(stage: string): number;
6
+ //# sourceMappingURL=sleep-level.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sleep-level.d.ts","sourceRoot":"","sources":["../../../src/garmin/maps/sleep-level.ts"],"names":[],"mappings":"AAeA;;;GAGG;AACH,wBAAgB,aAAa,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAEnD"}
@@ -0,0 +1,21 @@
1
+ // ─── Garmin Sleep Stage → Terra SleepLevel ────────────────────────────────────
2
+ // Maps Garmin sleep stage names to Terra's SleepLevel numeric enum.
3
+ //
4
+ // Garmin provides sleep levels as named map keys in sleepLevelsMap:
5
+ // { deep: [...], light: [...], rem: [...], awake: [...] }
6
+ //
7
+ // Terra SleepLevel: 0=Unknown, 1=Awake, 2=Sleeping, 3=OutOfBed, 4=Light, 5=Deep, 6=REM
8
+ const sleepLevelMap = {
9
+ deep: 5, // Deep → Terra Deep
10
+ light: 4, // Light → Terra Light
11
+ rem: 6, // REM → Terra REM
12
+ awake: 1, // Awake → Terra Awake
13
+ };
14
+ /**
15
+ * Map a Garmin sleep stage name to the Terra SleepLevel enum.
16
+ * Returns 0 (Unknown) for unrecognized stages.
17
+ */
18
+ export function mapSleepLevel(stage) {
19
+ return sleepLevelMap[stage] ?? 0;
20
+ }
21
+ //# sourceMappingURL=sleep-level.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sleep-level.js","sourceRoot":"","sources":["../../../src/garmin/maps/sleep-level.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,oEAAoE;AACpE,EAAE;AACF,oEAAoE;AACpE,4DAA4D;AAC5D,EAAE;AACF,uFAAuF;AAEvF,MAAM,aAAa,GAA2B;IAC5C,IAAI,EAAE,CAAC,EAAI,oBAAoB;IAC/B,KAAK,EAAE,CAAC,EAAG,sBAAsB;IACjC,GAAG,EAAE,CAAC,EAAK,kBAAkB;IAC7B,KAAK,EAAE,CAAC,EAAG,sBAAsB;CAClC,CAAC;AAEF;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,KAAa;IACzC,OAAO,aAAa,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;AACnC,CAAC"}
@@ -0,0 +1,23 @@
1
+ import type { GarminMenstrualCycleData } from "./types.js";
2
+ export type MenstruationData = ReturnType<typeof transformMenstruation>;
3
+ /**
4
+ * Transform a Garmin menstrual cycle record into a Soma Menstruation document shape.
5
+ *
6
+ * @param data - The Garmin menstrual cycle data from the Health API
7
+ * @returns Soma Menstruation fields (without connectionId/userId)
8
+ */
9
+ export declare function transformMenstruation(data: GarminMenstrualCycleData): {
10
+ metadata: {
11
+ start_time: string;
12
+ end_time: string;
13
+ };
14
+ menstruation_data: {
15
+ day_in_cycle: number | undefined;
16
+ current_phase: string | undefined;
17
+ length_of_current_phase_days: number | undefined;
18
+ period_length_days: number | undefined;
19
+ predicted_cycle_length_days: number | undefined;
20
+ is_predicted_cycle: string | undefined;
21
+ };
22
+ };
23
+ //# sourceMappingURL=menstruation.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menstruation.d.ts","sourceRoot":"","sources":["../../src/garmin/menstruation.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D,MAAM,MAAM,gBAAgB,GAAG,UAAU,CAAC,OAAO,qBAAqB,CAAC,CAAC;AAExE;;;;;GAKG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,wBAAwB;;;;;;;;;;;;;EA4BnE"}
@@ -0,0 +1,34 @@
1
+ // ─── Menstruation Transformer ────────────────────────────────────────────────
2
+ // Transforms Garmin menstrual cycle data into the Soma Menstruation schema shape.
3
+ /**
4
+ * Transform a Garmin menstrual cycle record into a Soma Menstruation document shape.
5
+ *
6
+ * @param data - The Garmin menstrual cycle data from the Health API
7
+ * @returns Soma Menstruation fields (without connectionId/userId)
8
+ */
9
+ export function transformMenstruation(data) {
10
+ const dateStr = data.calendarDate;
11
+ const startTime = data.startTimeInSeconds
12
+ ? new Date(data.startTimeInSeconds * 1000).toISOString()
13
+ : `${dateStr}T00:00:00.000Z`;
14
+ const endTime = data.startTimeInSeconds
15
+ ? new Date((data.startTimeInSeconds + 86400) * 1000).toISOString()
16
+ : `${dateStr}T23:59:59.999Z`;
17
+ return {
18
+ metadata: {
19
+ start_time: startTime,
20
+ end_time: endTime,
21
+ },
22
+ menstruation_data: {
23
+ day_in_cycle: data.dayInCycle,
24
+ current_phase: data.currentPhase?.toLowerCase(),
25
+ length_of_current_phase_days: data.lengthOfCurrentPhase,
26
+ period_length_days: data.periodLength,
27
+ predicted_cycle_length_days: data.predictedCycleLength,
28
+ is_predicted_cycle: data.isPredictedCycle != null
29
+ ? String(data.isPredictedCycle)
30
+ : undefined,
31
+ },
32
+ };
33
+ }
34
+ //# sourceMappingURL=menstruation.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"menstruation.js","sourceRoot":"","sources":["../../src/garmin/menstruation.ts"],"names":[],"mappings":"AAAA,gFAAgF;AAChF,kFAAkF;AAMlF;;;;;GAKG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAA8B;IAClE,MAAM,OAAO,GAAG,IAAI,CAAC,YAAY,CAAC;IAClC,MAAM,SAAS,GAAG,IAAI,CAAC,kBAAkB;QACvC,CAAC,CAAC,IAAI,IAAI,CAAC,IAAI,CAAC,kBAAkB,GAAG,IAAI,CAAC,CAAC,WAAW,EAAE;QACxD,CAAC,CAAC,GAAG,OAAO,gBAAgB,CAAC;IAC/B,MAAM,OAAO,GAAG,IAAI,CAAC,kBAAkB;QACrC,CAAC,CAAC,IAAI,IAAI,CACN,CAAC,IAAI,CAAC,kBAAkB,GAAG,KAAK,CAAC,GAAG,IAAI,CACzC,CAAC,WAAW,EAAE;QACjB,CAAC,CAAC,GAAG,OAAO,gBAAgB,CAAC;IAE/B,OAAO;QACL,QAAQ,EAAE;YACR,UAAU,EAAE,SAAS;YACrB,QAAQ,EAAE,OAAO;SAClB;QAED,iBAAiB,EAAE;YACjB,YAAY,EAAE,IAAI,CAAC,UAAU;YAC7B,aAAa,EAAE,IAAI,CAAC,YAAY,EAAE,WAAW,EAAE;YAC/C,4BAA4B,EAAE,IAAI,CAAC,oBAAoB;YACvD,kBAAkB,EAAE,IAAI,CAAC,YAAY;YACrC,2BAA2B,EAAE,IAAI,CAAC,oBAAoB;YACtD,kBAAkB,EAAE,IAAI,CAAC,gBAAgB,IAAI,IAAI;gBAC/C,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,gBAAgB,CAAC;gBAC/B,CAAC,CAAC,SAAS;SACd;KACF,CAAC;AACJ,CAAC"}
@@ -0,0 +1,62 @@
1
+ import type { GarminSleep } from "./types.js";
2
+ export type SleepData = ReturnType<typeof transformSleep>;
3
+ /**
4
+ * Transform a Garmin sleep session into a Soma Sleep document shape.
5
+ *
6
+ * @param sleep - The Garmin sleep data from the Health API
7
+ * @returns Soma Sleep fields (without connectionId/userId)
8
+ */
9
+ export declare function transformSleep(sleep: GarminSleep): {
10
+ metadata: {
11
+ summary_id: string;
12
+ start_time: string;
13
+ end_time: string;
14
+ upload_type: number;
15
+ };
16
+ sleep_durations_data: {
17
+ asleep: {
18
+ duration_asleep_state_seconds: number | undefined;
19
+ duration_deep_sleep_state_seconds: number | undefined;
20
+ duration_light_sleep_state_seconds: number | undefined;
21
+ duration_REM_sleep_state_seconds: number | undefined;
22
+ };
23
+ awake: {
24
+ duration_awake_state_seconds: number | undefined;
25
+ };
26
+ other: {
27
+ duration_in_bed_seconds: number;
28
+ duration_unmeasurable_sleep_seconds: number | undefined;
29
+ };
30
+ hypnogram_samples: {
31
+ timestamp: string;
32
+ level: number;
33
+ }[] | undefined;
34
+ };
35
+ heart_rate_data: {
36
+ detailed: {
37
+ hr_samples: {
38
+ timestamp: string;
39
+ bpm: number;
40
+ }[];
41
+ };
42
+ } | undefined;
43
+ respiration_data: {
44
+ breaths_data: {
45
+ avg_breaths_per_min: number | undefined;
46
+ min_breaths_per_min: number | undefined;
47
+ max_breaths_per_min: number | undefined;
48
+ samples: {
49
+ timestamp: string;
50
+ breaths_per_min: number;
51
+ }[] | undefined;
52
+ } | undefined;
53
+ oxygen_saturation_data: {
54
+ avg_saturation_percentage: number | undefined;
55
+ samples: {
56
+ timestamp: string;
57
+ percentage: number;
58
+ }[];
59
+ } | undefined;
60
+ } | undefined;
61
+ };
62
+ //# sourceMappingURL=sleep.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sleep.d.ts","sourceRoot":"","sources":["../../src/garmin/sleep.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,WAAW,EAAoB,MAAM,YAAY,CAAC;AAGhE,MAAM,MAAM,SAAS,GAAG,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;AAE1D;;;;;GAKG;AACH,wBAAgB,cAAc,CAAC,KAAK,EAAE,WAAW;;;;;;;;;;;;;;;;;;;;;;uBAyDb,MAAM;mBAAS,MAAM;;;;;;;;;;;;;;;;;;;;;;;;;;;;;EA/BxD"}
@@ -0,0 +1,125 @@
1
+ // ─── Sleep Transformer ───────────────────────────────────────────────────────
2
+ // Transforms a Garmin sleep session into the Soma Sleep schema shape.
3
+ import { mapSleepLevel } from "./maps/sleep-level.js";
4
+ /**
5
+ * Transform a Garmin sleep session into a Soma Sleep document shape.
6
+ *
7
+ * @param sleep - The Garmin sleep data from the Health API
8
+ * @returns Soma Sleep fields (without connectionId/userId)
9
+ */
10
+ export function transformSleep(sleep) {
11
+ const startMs = sleep.startTimeInSeconds * 1000;
12
+ const endMs = startMs + sleep.durationInSeconds * 1000;
13
+ const uploadTypeMap = {
14
+ ENHANCED_FINAL: 2, // Automatic
15
+ ENHANCED_TENTATIVE: 4, // Indeterminate
16
+ AUTO_FINAL: 2, // Automatic
17
+ AUTO_TENTATIVE: 4, // Indeterminate
18
+ MANUAL: 1, // Manual
19
+ };
20
+ return {
21
+ metadata: {
22
+ summary_id: sleep.summaryId,
23
+ start_time: new Date(startMs).toISOString(),
24
+ end_time: new Date(endMs).toISOString(),
25
+ upload_type: uploadTypeMap[sleep.validation] ?? 0,
26
+ },
27
+ sleep_durations_data: buildSleepDurationsData(sleep),
28
+ heart_rate_data: buildHeartRateData(sleep),
29
+ respiration_data: buildRespirationData(sleep),
30
+ };
31
+ }
32
+ // ─── Helpers ──────────────────────────────────────────────────────────────────
33
+ function buildSleepDurationsData(sleep) {
34
+ const totalAsleep = (sleep.deepSleepDurationInSeconds ?? 0) +
35
+ (sleep.lightSleepDurationInSeconds ?? 0) +
36
+ (sleep.remSleepInSeconds ?? 0);
37
+ return {
38
+ asleep: {
39
+ duration_asleep_state_seconds: totalAsleep || undefined,
40
+ duration_deep_sleep_state_seconds: sleep.deepSleepDurationInSeconds,
41
+ duration_light_sleep_state_seconds: sleep.lightSleepDurationInSeconds,
42
+ duration_REM_sleep_state_seconds: sleep.remSleepInSeconds,
43
+ },
44
+ awake: {
45
+ duration_awake_state_seconds: sleep.awakeDurationInSeconds,
46
+ },
47
+ other: {
48
+ duration_in_bed_seconds: sleep.durationInSeconds,
49
+ duration_unmeasurable_sleep_seconds: sleep.unmeasurableSleepInSeconds,
50
+ },
51
+ hypnogram_samples: buildHypnogramSamples(sleep),
52
+ };
53
+ }
54
+ function buildHypnogramSamples(sleep) {
55
+ if (!sleep.sleepLevelsMap)
56
+ return undefined;
57
+ const samples = [];
58
+ for (const [stage, levels] of Object.entries(sleep.sleepLevelsMap)) {
59
+ if (!levels)
60
+ continue;
61
+ const terraLevel = mapSleepLevel(stage);
62
+ for (const level of levels) {
63
+ samples.push({
64
+ timestamp: new Date(level.startTimeInSeconds * 1000).toISOString(),
65
+ level: terraLevel,
66
+ });
67
+ }
68
+ }
69
+ samples.sort((a, b) => new Date(a.timestamp).getTime() - new Date(b.timestamp).getTime());
70
+ return samples.length > 0 ? samples : undefined;
71
+ }
72
+ function buildHeartRateData(sleep) {
73
+ if (!sleep.timeOffsetHeartRateSamples ||
74
+ Object.keys(sleep.timeOffsetHeartRateSamples).length === 0) {
75
+ return undefined;
76
+ }
77
+ const hrSamples = Object.entries(sleep.timeOffsetHeartRateSamples).map(([offset, bpm]) => ({
78
+ timestamp: new Date((sleep.startTimeInSeconds + parseInt(offset, 10)) * 1000).toISOString(),
79
+ bpm,
80
+ }));
81
+ return {
82
+ detailed: { hr_samples: hrSamples },
83
+ };
84
+ }
85
+ function buildRespirationData(sleep) {
86
+ const hasBreathSummary = sleep.averageRespirationInBreathsPerMinute != null;
87
+ const hasBreathSamples = sleep.timeOffsetSleepRespiration != null &&
88
+ Object.keys(sleep.timeOffsetSleepRespiration).length > 0;
89
+ const hasSpO2Samples = sleep.timeOffsetSpo2Values != null &&
90
+ Object.keys(sleep.timeOffsetSpo2Values).length > 0;
91
+ if (!hasBreathSummary && !hasBreathSamples && !hasSpO2Samples) {
92
+ return undefined;
93
+ }
94
+ const breathSamples = hasBreathSamples
95
+ ? Object.entries(sleep.timeOffsetSleepRespiration).map(([offset, rate]) => ({
96
+ timestamp: new Date((sleep.startTimeInSeconds + parseInt(offset, 10)) * 1000).toISOString(),
97
+ breaths_per_min: rate,
98
+ }))
99
+ : undefined;
100
+ const spo2Samples = hasSpO2Samples
101
+ ? Object.entries(sleep.timeOffsetSpo2Values).map(([offset, pct]) => ({
102
+ timestamp: new Date((sleep.startTimeInSeconds + parseInt(offset, 10)) * 1000).toISOString(),
103
+ percentage: pct,
104
+ }))
105
+ : undefined;
106
+ return {
107
+ breaths_data: hasBreathSummary || (breathSamples && breathSamples.length > 0)
108
+ ? {
109
+ avg_breaths_per_min: sleep.averageRespirationInBreathsPerMinute,
110
+ min_breaths_per_min: sleep.lowestRespirationInBreathsPerMinute,
111
+ max_breaths_per_min: sleep.highestRespirationInBreathsPerMinute,
112
+ samples: breathSamples && breathSamples.length > 0
113
+ ? breathSamples
114
+ : undefined,
115
+ }
116
+ : undefined,
117
+ oxygen_saturation_data: spo2Samples && spo2Samples.length > 0
118
+ ? {
119
+ avg_saturation_percentage: sleep.averageSpo2Value,
120
+ samples: spo2Samples,
121
+ }
122
+ : undefined,
123
+ };
124
+ }
125
+ //# sourceMappingURL=sleep.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sleep.js","sourceRoot":"","sources":["../../src/garmin/sleep.ts"],"names":[],"mappings":"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"}