@nativesquare/soma 0.16.2 → 0.16.3
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.
- package/dist/client/healthkit.d.ts +4 -84
- package/dist/client/healthkit.d.ts.map +1 -1
- package/dist/client/healthkit.js +13 -505
- package/dist/client/healthkit.js.map +1 -1
- package/dist/component/_generated/api.d.ts +4 -0
- package/dist/component/_generated/api.d.ts.map +1 -1
- package/dist/component/_generated/api.js.map +1 -1
- package/dist/component/_generated/component.d.ts +472 -0
- package/dist/component/_generated/component.d.ts.map +1 -1
- package/dist/component/healthkit/index.d.ts +1 -0
- package/dist/component/healthkit/index.d.ts.map +1 -1
- package/dist/component/healthkit/index.js +5 -0
- package/dist/component/healthkit/index.js.map +1 -1
- package/dist/component/healthkit/public.d.ts +451 -0
- package/dist/component/healthkit/public.d.ts.map +1 -0
- package/dist/component/healthkit/public.js +386 -0
- package/dist/component/healthkit/public.js.map +1 -0
- package/dist/component/healthkit/types.d.ts +13 -76
- package/dist/component/healthkit/types.d.ts.map +1 -1
- package/dist/component/healthkit/types.js +9 -6
- package/dist/component/healthkit/types.js.map +1 -1
- package/dist/component/healthkit/validators.d.ts +1933 -0
- package/dist/component/healthkit/validators.d.ts.map +1 -0
- package/dist/component/healthkit/validators.js +199 -0
- package/dist/component/healthkit/validators.js.map +1 -0
- package/dist/component/strava/types/stravaApi/zod.gen.d.ts +3 -3
- package/package.json +1 -1
- package/src/client/healthkit.ts +43 -624
- package/src/component/_generated/api.ts +4 -0
- package/src/component/_generated/component.ts +412 -0
- package/src/component/healthkit/index.ts +74 -46
- package/src/component/healthkit/public.ts +597 -0
- package/src/component/healthkit/types.ts +45 -114
- package/src/component/healthkit/validators.ts +253 -0
|
@@ -1,112 +1,49 @@
|
|
|
1
1
|
// ─── Apple HealthKit Input Types ──────────────────────────────────────────────
|
|
2
|
-
// Library-agnostic TypeScript
|
|
2
|
+
// Library-agnostic TypeScript types representing HealthKit data shapes.
|
|
3
3
|
// Compatible with @kingstinct/react-native-healthkit, react-native-health,
|
|
4
4
|
// expo-health, or any custom native module.
|
|
5
5
|
//
|
|
6
|
-
// These types
|
|
7
|
-
//
|
|
8
|
-
//
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
export
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
// ─── Category Sample ─────────────────────────────────────────────────────────
|
|
42
|
-
// Represents a categorized observation (sleep stage, menstrual flow, etc.)
|
|
43
|
-
|
|
44
|
-
export interface HKCategorySample {
|
|
45
|
-
uuid: string;
|
|
46
|
-
sampleType: HKCategoryTypeIdentifier;
|
|
47
|
-
startDate: string; // ISO-8601
|
|
48
|
-
endDate: string; // ISO-8601
|
|
49
|
-
value: number; // Category-specific enum value
|
|
50
|
-
source?: HKSource;
|
|
51
|
-
device?: HKDevice;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
// ─── Workout ─────────────────────────────────────────────────────────────────
|
|
55
|
-
|
|
56
|
-
export interface HKWorkoutRoute {
|
|
57
|
-
locations: Array<{
|
|
58
|
-
latitude: number;
|
|
59
|
-
longitude: number;
|
|
60
|
-
altitude?: number;
|
|
61
|
-
timestamp: string; // ISO-8601
|
|
62
|
-
}>;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
export interface HKWorkout {
|
|
66
|
-
uuid: string;
|
|
67
|
-
workoutActivityType: number; // HKWorkoutActivityType raw value
|
|
68
|
-
startDate: string; // ISO-8601
|
|
69
|
-
endDate: string; // ISO-8601
|
|
70
|
-
duration: number; // seconds
|
|
71
|
-
totalEnergyBurned?: number; // kcal
|
|
72
|
-
totalDistance?: number; // meters
|
|
73
|
-
totalSwimmingStrokeCount?: number;
|
|
74
|
-
totalFlightsClimbed?: number;
|
|
75
|
-
source?: HKSource;
|
|
76
|
-
device?: HKDevice;
|
|
77
|
-
// Associated samples (queried separately in HealthKit, attached by host app)
|
|
78
|
-
heartRateSamples?: HKQuantitySample[];
|
|
79
|
-
routeData?: HKWorkoutRoute[];
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
// ─── Activity Summary ────────────────────────────────────────────────────────
|
|
83
|
-
// Daily activity ring data from HealthKit
|
|
84
|
-
|
|
85
|
-
export interface HKActivitySummary {
|
|
86
|
-
activeEnergyBurned: number; // kcal
|
|
87
|
-
activeEnergyBurnedGoal: number; // kcal
|
|
88
|
-
appleExerciseTime: number; // minutes
|
|
89
|
-
appleExerciseTimeGoal: number; // minutes
|
|
90
|
-
appleStandHours: number; // count
|
|
91
|
-
appleStandHoursGoal: number; // count
|
|
92
|
-
dateComponents: { year: number; month: number; day: number };
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// ─── User Characteristics ────────────────────────────────────────────────────
|
|
96
|
-
// Static user profile data from HealthKit
|
|
97
|
-
|
|
98
|
-
export interface HKCharacteristics {
|
|
99
|
-
biologicalSex?: HKBiologicalSex;
|
|
100
|
-
dateOfBirth?: string; // ISO-8601 date
|
|
101
|
-
bloodType?: string;
|
|
102
|
-
fitzpatrickSkinType?: number;
|
|
103
|
-
wheelchairUse?: boolean;
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
export type HKBiologicalSex = "female" | "male" | "other" | "notSet";
|
|
6
|
+
// These types are INFERRED from the Convex validators in ./validators.js —
|
|
7
|
+
// edit validators.ts to change shapes, not this file. The identifier unions
|
|
8
|
+
// and runtime enum constants at the bottom are hand-written: they exist as
|
|
9
|
+
// documentation / autocomplete aids only and are not enforced at runtime.
|
|
10
|
+
|
|
11
|
+
import type { Infer } from "convex/values";
|
|
12
|
+
import {
|
|
13
|
+
hkDeviceValidator,
|
|
14
|
+
hkSourceValidator,
|
|
15
|
+
hkQuantitySampleValidator,
|
|
16
|
+
hkCategorySampleValidator,
|
|
17
|
+
hkWorkoutRouteValidator,
|
|
18
|
+
hkWorkoutValidator,
|
|
19
|
+
hkActivitySummaryValidator,
|
|
20
|
+
hkCharacteristicsValidator,
|
|
21
|
+
hkBiologicalSexValidator,
|
|
22
|
+
hkSleepCategoryValueValidator,
|
|
23
|
+
hkMenstrualFlowCategoryValueValidator,
|
|
24
|
+
} from "./validators.js";
|
|
25
|
+
|
|
26
|
+
// ─── Inferred shapes ─────────────────────────────────────────────────────────
|
|
27
|
+
|
|
28
|
+
export type HKDevice = Infer<typeof hkDeviceValidator>;
|
|
29
|
+
export type HKSource = Infer<typeof hkSourceValidator>;
|
|
30
|
+
export type HKQuantitySample = Infer<typeof hkQuantitySampleValidator>;
|
|
31
|
+
export type HKCategorySample = Infer<typeof hkCategorySampleValidator>;
|
|
32
|
+
export type HKWorkoutRoute = Infer<typeof hkWorkoutRouteValidator>;
|
|
33
|
+
export type HKWorkout = Infer<typeof hkWorkoutValidator>;
|
|
34
|
+
export type HKActivitySummary = Infer<typeof hkActivitySummaryValidator>;
|
|
35
|
+
export type HKCharacteristics = Infer<typeof hkCharacteristicsValidator>;
|
|
36
|
+
export type HKBiologicalSex = Infer<typeof hkBiologicalSexValidator>;
|
|
37
|
+
export type HKSleepCategoryValue = Infer<typeof hkSleepCategoryValueValidator>;
|
|
38
|
+
export type HKMenstrualFlowCategoryValue = Infer<
|
|
39
|
+
typeof hkMenstrualFlowCategoryValueValidator
|
|
40
|
+
>;
|
|
107
41
|
|
|
108
42
|
// ─── HealthKit Quantity Type Identifiers ─────────────────────────────────────
|
|
109
|
-
//
|
|
43
|
+
// Documentary union of known identifiers. The runtime validator is a bare
|
|
44
|
+
// `v.string()` — any string is accepted. Use this type for host-side
|
|
45
|
+
// autocomplete by annotating values you construct, e.g.
|
|
46
|
+
// `const t: HKQuantityTypeIdentifier = "HKQuantityTypeIdentifierHeartRate"`.
|
|
110
47
|
|
|
111
48
|
export type HKQuantityTypeIdentifier =
|
|
112
49
|
// Body measurements
|
|
@@ -178,9 +115,9 @@ export type HKQuantityTypeIdentifier =
|
|
|
178
115
|
| "HKQuantityTypeIdentifierDietaryCaffeine"
|
|
179
116
|
| "HKQuantityTypeIdentifierDietaryIodine"
|
|
180
117
|
| "HKQuantityTypeIdentifierDietaryChloride"
|
|
181
|
-
// Hydration
|
|
182
118
|
| "HKQuantityTypeIdentifierDietaryPanthothenicAcid"
|
|
183
|
-
// Catch-all for future types
|
|
119
|
+
// Catch-all for future types (preserves autocomplete on the known literals
|
|
120
|
+
// while accepting any string, matching the runtime `v.string()` validator).
|
|
184
121
|
| (string & {});
|
|
185
122
|
|
|
186
123
|
// ─── HealthKit Category Type Identifiers ─────────────────────────────────────
|
|
@@ -191,7 +128,9 @@ export type HKCategoryTypeIdentifier =
|
|
|
191
128
|
| "HKCategoryTypeIdentifierAppleStandHour"
|
|
192
129
|
| (string & {});
|
|
193
130
|
|
|
194
|
-
// ───
|
|
131
|
+
// ─── Runtime enum constants ──────────────────────────────────────────────────
|
|
132
|
+
// Kept as real values (not just types) so host code can compare against them
|
|
133
|
+
// at runtime: `if (sample.value === HKSleepCategory.AsleepREM) { ... }`
|
|
195
134
|
|
|
196
135
|
export const HKSleepCategory = {
|
|
197
136
|
InBed: 0,
|
|
@@ -202,11 +141,6 @@ export const HKSleepCategory = {
|
|
|
202
141
|
AsleepREM: 5,
|
|
203
142
|
} as const;
|
|
204
143
|
|
|
205
|
-
export type HKSleepCategoryValue =
|
|
206
|
-
(typeof HKSleepCategory)[keyof typeof HKSleepCategory];
|
|
207
|
-
|
|
208
|
-
// ─── HealthKit Menstrual Flow Values ─────────────────────────────────────────
|
|
209
|
-
|
|
210
144
|
export const HKMenstrualFlowCategory = {
|
|
211
145
|
Unspecified: 1,
|
|
212
146
|
Light: 2,
|
|
@@ -214,6 +148,3 @@ export const HKMenstrualFlowCategory = {
|
|
|
214
148
|
Heavy: 4,
|
|
215
149
|
None: 5,
|
|
216
150
|
} as const;
|
|
217
|
-
|
|
218
|
-
export type HKMenstrualFlowCategoryValue =
|
|
219
|
-
(typeof HKMenstrualFlowCategory)[keyof typeof HKMenstrualFlowCategory];
|
|
@@ -0,0 +1,253 @@
|
|
|
1
|
+
// ─── HealthKit Input Validators ──────────────────────────────────────────────
|
|
2
|
+
// Convex validators for the library-agnostic HealthKit input shapes the host
|
|
3
|
+
// app hands to Soma. TypeScript types in ./types.js are inferred from these.
|
|
4
|
+
//
|
|
5
|
+
// Keep in lockstep with the documented HKQuantityTypeIdentifier /
|
|
6
|
+
// HKCategoryTypeIdentifier string-literal unions in types.ts. Those unions are
|
|
7
|
+
// documentation / autocomplete aids only; at runtime we accept any string so
|
|
8
|
+
// that future iOS HealthKit identifiers don't require a Soma release.
|
|
9
|
+
|
|
10
|
+
import { v } from "convex/values";
|
|
11
|
+
import { somaErrorValidator } from "../validators/shared.js";
|
|
12
|
+
|
|
13
|
+
// ─── Primitive shapes ───────────────────────────────────────────────────────
|
|
14
|
+
|
|
15
|
+
export const hkDeviceValidator = v.object({
|
|
16
|
+
name: v.optional(v.string()),
|
|
17
|
+
manufacturer: v.optional(v.string()),
|
|
18
|
+
model: v.optional(v.string()),
|
|
19
|
+
hardwareVersion: v.optional(v.string()),
|
|
20
|
+
softwareVersion: v.optional(v.string()),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
export const hkSourceValidator = v.object({
|
|
24
|
+
name: v.string(),
|
|
25
|
+
bundleIdentifier: v.string(),
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
// ─── Enums ──────────────────────────────────────────────────────────────────
|
|
29
|
+
|
|
30
|
+
/**
|
|
31
|
+
* Biological sex values produced by HealthKit.
|
|
32
|
+
* Matches the `HKBiologicalSex` string union in types.ts.
|
|
33
|
+
*/
|
|
34
|
+
export const hkBiologicalSexValidator = v.union(
|
|
35
|
+
v.literal("female"),
|
|
36
|
+
v.literal("male"),
|
|
37
|
+
v.literal("other"),
|
|
38
|
+
v.literal("notSet"),
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Numeric sleep-stage value from `HKCategoryTypeIdentifierSleepAnalysis`:
|
|
43
|
+
* 0=InBed, 1=AsleepUnspecified, 2=Awake, 3=AsleepCore, 4=AsleepDeep, 5=AsleepREM.
|
|
44
|
+
*/
|
|
45
|
+
export const hkSleepCategoryValueValidator = v.union(
|
|
46
|
+
v.literal(0),
|
|
47
|
+
v.literal(1),
|
|
48
|
+
v.literal(2),
|
|
49
|
+
v.literal(3),
|
|
50
|
+
v.literal(4),
|
|
51
|
+
v.literal(5),
|
|
52
|
+
);
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Numeric menstrual flow value from `HKCategoryTypeIdentifierMenstrualFlow`:
|
|
56
|
+
* 1=Unspecified, 2=Light, 3=Medium, 4=Heavy, 5=None.
|
|
57
|
+
*/
|
|
58
|
+
export const hkMenstrualFlowCategoryValueValidator = v.union(
|
|
59
|
+
v.literal(1),
|
|
60
|
+
v.literal(2),
|
|
61
|
+
v.literal(3),
|
|
62
|
+
v.literal(4),
|
|
63
|
+
v.literal(5),
|
|
64
|
+
);
|
|
65
|
+
|
|
66
|
+
// ─── Samples ────────────────────────────────────────────────────────────────
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Numeric measurement from HealthKit (heart rate, steps, weight, etc.).
|
|
70
|
+
*
|
|
71
|
+
* `sampleType` is a bare string for forward-compat with iOS updates that add
|
|
72
|
+
* new identifiers. The `HKQuantityTypeIdentifier` alias in types.ts lists
|
|
73
|
+
* known values for host-side autocomplete; it is not enforced at runtime.
|
|
74
|
+
*/
|
|
75
|
+
export const hkQuantitySampleValidator = v.object({
|
|
76
|
+
uuid: v.string(),
|
|
77
|
+
sampleType: v.string(),
|
|
78
|
+
startDate: v.string(),
|
|
79
|
+
endDate: v.string(),
|
|
80
|
+
value: v.number(),
|
|
81
|
+
unit: v.string(),
|
|
82
|
+
source: v.optional(hkSourceValidator),
|
|
83
|
+
device: v.optional(hkDeviceValidator),
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Categorized observation (sleep stage, menstrual flow, etc.).
|
|
88
|
+
*
|
|
89
|
+
* `value` is a category-specific enum integer. `sampleType` is a bare string
|
|
90
|
+
* for the same forward-compat reason as on `HKQuantitySample`.
|
|
91
|
+
*/
|
|
92
|
+
export const hkCategorySampleValidator = v.object({
|
|
93
|
+
uuid: v.string(),
|
|
94
|
+
sampleType: v.string(),
|
|
95
|
+
startDate: v.string(),
|
|
96
|
+
endDate: v.string(),
|
|
97
|
+
value: v.number(),
|
|
98
|
+
source: v.optional(hkSourceValidator),
|
|
99
|
+
device: v.optional(hkDeviceValidator),
|
|
100
|
+
});
|
|
101
|
+
|
|
102
|
+
// ─── Workout ────────────────────────────────────────────────────────────────
|
|
103
|
+
|
|
104
|
+
export const hkWorkoutRouteValidator = v.object({
|
|
105
|
+
locations: v.array(
|
|
106
|
+
v.object({
|
|
107
|
+
latitude: v.number(),
|
|
108
|
+
longitude: v.number(),
|
|
109
|
+
altitude: v.optional(v.number()),
|
|
110
|
+
timestamp: v.string(),
|
|
111
|
+
}),
|
|
112
|
+
),
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
export const hkWorkoutValidator = v.object({
|
|
116
|
+
uuid: v.string(),
|
|
117
|
+
workoutActivityType: v.number(),
|
|
118
|
+
startDate: v.string(),
|
|
119
|
+
endDate: v.string(),
|
|
120
|
+
duration: v.number(),
|
|
121
|
+
totalEnergyBurned: v.optional(v.number()),
|
|
122
|
+
totalDistance: v.optional(v.number()),
|
|
123
|
+
totalSwimmingStrokeCount: v.optional(v.number()),
|
|
124
|
+
totalFlightsClimbed: v.optional(v.number()),
|
|
125
|
+
source: v.optional(hkSourceValidator),
|
|
126
|
+
device: v.optional(hkDeviceValidator),
|
|
127
|
+
heartRateSamples: v.optional(v.array(hkQuantitySampleValidator)),
|
|
128
|
+
routeData: v.optional(v.array(hkWorkoutRouteValidator)),
|
|
129
|
+
});
|
|
130
|
+
|
|
131
|
+
// ─── Activity Summary ───────────────────────────────────────────────────────
|
|
132
|
+
|
|
133
|
+
export const hkActivitySummaryValidator = v.object({
|
|
134
|
+
activeEnergyBurned: v.number(),
|
|
135
|
+
activeEnergyBurnedGoal: v.number(),
|
|
136
|
+
appleExerciseTime: v.number(),
|
|
137
|
+
appleExerciseTimeGoal: v.number(),
|
|
138
|
+
appleStandHours: v.number(),
|
|
139
|
+
appleStandHoursGoal: v.number(),
|
|
140
|
+
dateComponents: v.object({
|
|
141
|
+
year: v.number(),
|
|
142
|
+
month: v.number(),
|
|
143
|
+
day: v.number(),
|
|
144
|
+
}),
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// ─── Characteristics ────────────────────────────────────────────────────────
|
|
148
|
+
|
|
149
|
+
export const hkCharacteristicsValidator = v.object({
|
|
150
|
+
biologicalSex: v.optional(hkBiologicalSexValidator),
|
|
151
|
+
dateOfBirth: v.optional(v.string()),
|
|
152
|
+
bloodType: v.optional(v.string()),
|
|
153
|
+
fitzpatrickSkinType: v.optional(v.number()),
|
|
154
|
+
wheelchairUse: v.optional(v.boolean()),
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
// ─── Time range ─────────────────────────────────────────────────────────────
|
|
158
|
+
|
|
159
|
+
export const timeRangeValidator = v.object({
|
|
160
|
+
start_time: v.string(),
|
|
161
|
+
end_time: v.string(),
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
// ─── Per-mutation args ──────────────────────────────────────────────────────
|
|
165
|
+
// Plain object literals so they can be dropped straight into `args:` on a
|
|
166
|
+
// `mutation({ args, ... })` definition.
|
|
167
|
+
|
|
168
|
+
export const syncActivitiesArgs = {
|
|
169
|
+
userId: v.string(),
|
|
170
|
+
workouts: v.array(hkWorkoutValidator),
|
|
171
|
+
};
|
|
172
|
+
|
|
173
|
+
export const syncSleepArgs = {
|
|
174
|
+
userId: v.string(),
|
|
175
|
+
sessions: v.array(v.array(hkCategorySampleValidator)),
|
|
176
|
+
};
|
|
177
|
+
|
|
178
|
+
export const syncBodyArgs = {
|
|
179
|
+
userId: v.string(),
|
|
180
|
+
samples: v.array(hkQuantitySampleValidator),
|
|
181
|
+
timeRange: v.optional(timeRangeValidator),
|
|
182
|
+
};
|
|
183
|
+
|
|
184
|
+
export const syncDailyArgs = {
|
|
185
|
+
userId: v.string(),
|
|
186
|
+
samples: v.array(hkQuantitySampleValidator),
|
|
187
|
+
timeRange: v.optional(timeRangeValidator),
|
|
188
|
+
};
|
|
189
|
+
|
|
190
|
+
export const syncDailyFromSummaryArgs = {
|
|
191
|
+
userId: v.string(),
|
|
192
|
+
summaries: v.array(hkActivitySummaryValidator),
|
|
193
|
+
};
|
|
194
|
+
|
|
195
|
+
export const syncNutritionArgs = {
|
|
196
|
+
userId: v.string(),
|
|
197
|
+
samples: v.array(hkQuantitySampleValidator),
|
|
198
|
+
timeRange: v.optional(timeRangeValidator),
|
|
199
|
+
};
|
|
200
|
+
|
|
201
|
+
export const syncMenstruationArgs = {
|
|
202
|
+
userId: v.string(),
|
|
203
|
+
samples: v.array(hkCategorySampleValidator),
|
|
204
|
+
timeRange: v.optional(timeRangeValidator),
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
export const syncAthleteArgs = {
|
|
208
|
+
userId: v.string(),
|
|
209
|
+
characteristics: hkCharacteristicsValidator,
|
|
210
|
+
};
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* Args bag for `syncAll`. Every data-type field is optional — only provided
|
|
214
|
+
* types are synced. Use as: `mutation({ args: syncAllHealthKitArgs, ... })`
|
|
215
|
+
* or `args: v.object(syncAllHealthKitArgs)` on the host side.
|
|
216
|
+
*/
|
|
217
|
+
export const syncAllHealthKitArgs = {
|
|
218
|
+
userId: v.string(),
|
|
219
|
+
workouts: v.optional(v.array(hkWorkoutValidator)),
|
|
220
|
+
sleepSessions: v.optional(v.array(v.array(hkCategorySampleValidator))),
|
|
221
|
+
bodySamples: v.optional(v.array(hkQuantitySampleValidator)),
|
|
222
|
+
bodyTimeRange: v.optional(timeRangeValidator),
|
|
223
|
+
dailySamples: v.optional(v.array(hkQuantitySampleValidator)),
|
|
224
|
+
dailyTimeRange: v.optional(timeRangeValidator),
|
|
225
|
+
dailySummaries: v.optional(v.array(hkActivitySummaryValidator)),
|
|
226
|
+
nutritionSamples: v.optional(v.array(hkQuantitySampleValidator)),
|
|
227
|
+
nutritionTimeRange: v.optional(timeRangeValidator),
|
|
228
|
+
menstruationSamples: v.optional(v.array(hkCategorySampleValidator)),
|
|
229
|
+
menstruationTimeRange: v.optional(timeRangeValidator),
|
|
230
|
+
characteristics: v.optional(hkCharacteristicsValidator),
|
|
231
|
+
};
|
|
232
|
+
|
|
233
|
+
// ─── Return validators ──────────────────────────────────────────────────────
|
|
234
|
+
|
|
235
|
+
const countResult = (countKey: string) =>
|
|
236
|
+
v.object({
|
|
237
|
+
data: v.object({ [countKey]: v.number() }),
|
|
238
|
+
errors: v.array(somaErrorValidator),
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
export const syncActivitiesReturn = countResult("activities");
|
|
242
|
+
export const syncSleepReturn = countResult("sleep");
|
|
243
|
+
export const syncBodyReturn = countResult("body");
|
|
244
|
+
export const syncDailyReturn = countResult("daily");
|
|
245
|
+
export const syncNutritionReturn = countResult("nutrition");
|
|
246
|
+
export const syncMenstruationReturn = countResult("menstruation");
|
|
247
|
+
export const syncAthleteReturn = countResult("athletes");
|
|
248
|
+
|
|
249
|
+
/** syncAll aggregates counts across data types; keys are not enumerated. */
|
|
250
|
+
export const syncAllReturn = v.object({
|
|
251
|
+
data: v.record(v.string(), v.number()),
|
|
252
|
+
errors: v.array(somaErrorValidator),
|
|
253
|
+
});
|