@tryterra/react-native 0.0.0-stage → 2.2.1

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 (112) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +142 -2
  3. package/TerraReactNative.podspec +48 -0
  4. package/android/build.gradle +87 -0
  5. package/android/src/bridgeCore/kotlin/README.md +1 -0
  6. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/BridgeBootstrap.kt +133 -0
  7. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/BridgeHost.kt +32 -0
  8. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/Conversions.kt +557 -0
  9. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/LauncherSlots.kt +41 -0
  10. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/ReadConversions.kt +250 -0
  11. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/Rejections.kt +150 -0
  12. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/StreamRegistry.kt +77 -0
  13. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/TerraBridge.kt +86 -0
  14. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/TerraBridgeOpsImpl.kt +300 -0
  15. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/TerraBridgeStreamsImpl.kt +50 -0
  16. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/TokenBroker.kt +198 -0
  17. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/generated/BridgeErrors.kt +217 -0
  18. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/generated/BridgeOps.kt +582 -0
  19. package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/generated/BridgeTypes.kt +1569 -0
  20. package/android/src/healthConnectOnly/kotlin/co/tryterra/sdk/reactnative/TerraStores.kt +11 -0
  21. package/android/src/main/AndroidManifest.xml +24 -0
  22. package/android/src/main/java/co/tryterra/sdk/reactnative/TerraBridgeModule.kt +96 -0
  23. package/android/src/main/java/co/tryterra/sdk/reactnative/TerraReactNativePackage.kt +26 -0
  24. package/android/src/main/java/co/tryterra/sdk/reactnative/TerraStartup.kt +46 -0
  25. package/android/src/samsung/kotlin/co/tryterra/sdk/reactnative/TerraStores.kt +13 -0
  26. package/docs/availability.md +396 -0
  27. package/frameworks/TerraSDK.xcframework/Info.plist +48 -0
  28. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Info.plist +0 -0
  29. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.abi.json +82672 -0
  30. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.package.swiftinterface +2186 -0
  31. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +2186 -0
  32. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  33. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.swiftinterface +2163 -0
  34. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/PrivacyInfo.xcprivacy +96 -0
  35. package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/TerraSDK +0 -0
  36. package/frameworks/TerraSDK.xcframework/ios-arm64/dSYMs/TerraSDK.framework.dSYM/Contents/Info.plist +20 -0
  37. package/frameworks/TerraSDK.xcframework/ios-arm64/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/DWARF/TerraSDK +0 -0
  38. package/frameworks/TerraSDK.xcframework/ios-arm64/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/Relocations/aarch64/TerraSDK.yml +6594 -0
  39. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Info.plist +0 -0
  40. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +82672 -0
  41. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.package.swiftinterface +2186 -0
  42. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +2186 -0
  43. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  44. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +2163 -0
  45. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json +82672 -0
  46. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.package.swiftinterface +2186 -0
  47. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +2186 -0
  48. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  49. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +2163 -0
  50. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/PrivacyInfo.xcprivacy +96 -0
  51. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/TerraSDK +0 -0
  52. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/_CodeSignature/CodeResources +223 -0
  53. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/TerraSDK.framework.dSYM/Contents/Info.plist +20 -0
  54. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/DWARF/TerraSDK +0 -0
  55. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/Relocations/aarch64/TerraSDK.yml +6595 -0
  56. package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/Relocations/x86_64/TerraSDK.yml +6513 -0
  57. package/ios/TerraBridgeCore/BridgeBootstrap.swift +89 -0
  58. package/ios/TerraBridgeCore/BridgeHost.swift +13 -0
  59. package/ios/TerraBridgeCore/Conversions+Reads.swift +259 -0
  60. package/ios/TerraBridgeCore/Conversions.swift +594 -0
  61. package/ios/TerraBridgeCore/Generated/BridgeErrors.swift +179 -0
  62. package/ios/TerraBridgeCore/Generated/BridgeOps.swift +967 -0
  63. package/ios/TerraBridgeCore/Generated/BridgeTypes.swift +2050 -0
  64. package/ios/TerraBridgeCore/Locked.swift +15 -0
  65. package/ios/TerraBridgeCore/README.md +1 -0
  66. package/ios/TerraBridgeCore/Rejections.swift +130 -0
  67. package/ios/TerraBridgeCore/RuntimeAttachment.swift +60 -0
  68. package/ios/TerraBridgeCore/StreamRegistry.swift +59 -0
  69. package/ios/TerraBridgeCore/TerraBridge.swift +122 -0
  70. package/ios/TerraBridgeCore/TerraBridgeOpsImpl.swift +318 -0
  71. package/ios/TerraBridgeCore/TerraBridgeStreamsImpl.swift +60 -0
  72. package/ios/TerraBridgeCore/TokenBroker.swift +147 -0
  73. package/ios/TerraBridgeModule.mm +79 -0
  74. package/ios/TerraBridgeModuleImpl.swift +49 -0
  75. package/ios/TerraReactNative.swift +19 -0
  76. package/lib/EndUser.d.ts +12 -0
  77. package/lib/EndUser.js +13 -0
  78. package/lib/NativeTerraBridge.d.ts +23 -0
  79. package/lib/NativeTerraBridge.js +13 -0
  80. package/lib/Terra.d.ts +223 -0
  81. package/lib/Terra.js +336 -0
  82. package/lib/TerraError.d.ts +42 -0
  83. package/lib/TerraError.js +95 -0
  84. package/lib/createTerra.d.ts +8 -0
  85. package/lib/createTerra.js +19 -0
  86. package/lib/generated/client.d.ts +128 -0
  87. package/lib/generated/client.js +256 -0
  88. package/lib/generated/codecs.d.ts +219 -0
  89. package/lib/generated/codecs.js +2066 -0
  90. package/lib/generated/errors.d.ts +13 -0
  91. package/lib/generated/errors.js +68 -0
  92. package/lib/generated/ops.d.ts +13 -0
  93. package/lib/generated/ops.js +161 -0
  94. package/lib/generated/streams.d.ts +23 -0
  95. package/lib/generated/streams.js +58 -0
  96. package/lib/generated/types.d.ts +794 -0
  97. package/lib/generated/types.js +224 -0
  98. package/lib/index.d.ts +29 -0
  99. package/lib/index.js +55 -0
  100. package/package.json +71 -4
  101. package/src/EndUser.ts +15 -0
  102. package/src/NativeTerraBridge.ts +27 -0
  103. package/src/Terra.ts +592 -0
  104. package/src/TerraError.ts +116 -0
  105. package/src/createTerra.ts +18 -0
  106. package/src/generated/client.ts +315 -0
  107. package/src/generated/codecs.ts +1989 -0
  108. package/src/generated/errors.ts +113 -0
  109. package/src/generated/ops.ts +233 -0
  110. package/src/generated/streams.ts +74 -0
  111. package/src/generated/types.ts +1222 -0
  112. package/src/index.ts +54 -0
@@ -0,0 +1,1569 @@
1
+ // Generated from surface/terra-surface.json by surface/gen. Do not edit by hand.
2
+ // Regenerate with: node surface/gen/src/cli.ts generate
3
+
4
+ package co.tryterra.sdk.bridge.generated
5
+
6
+ import kotlinx.serialization.ExperimentalSerializationApi
7
+ import kotlinx.serialization.SerializationException
8
+ import kotlinx.serialization.KSerializer
9
+ import kotlinx.serialization.SerialName
10
+ import kotlinx.serialization.Serializable
11
+ import kotlinx.serialization.builtins.ListSerializer
12
+ import kotlinx.serialization.descriptors.SerialDescriptor
13
+ import kotlinx.serialization.encoding.Decoder
14
+ import kotlinx.serialization.encoding.Encoder
15
+ import kotlinx.serialization.json.JsonClassDiscriminator
16
+ import kotlinx.serialization.json.JsonObject
17
+ import kotlinx.serialization.json.JsonPrimitive
18
+ import kotlinx.serialization.json.booleanOrNull
19
+ import kotlinx.serialization.json.doubleOrNull
20
+ import kotlinx.serialization.json.longOrNull
21
+ import java.time.Instant
22
+ import java.time.ZoneOffset
23
+ import java.time.format.DateTimeFormatter
24
+
25
+ /**
26
+ * The one spelling of an instant on the wire: UTC, and always exactly three fractional digits.
27
+ *
28
+ * `Instant.toString()` is not it: it omits the fractional part when it is zero and prints nine
29
+ * digits when it is not, so the same moment would produce different bytes here and in Swift.
30
+ * The DTOs carry instants as String, so this is the only place the format is decided, and the
31
+ * hand-written ops implementation must go through it rather than formatting its own.
32
+ */
33
+ public object BridgeInstant {
34
+ private val formatter: DateTimeFormatter =
35
+ DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'").withZone(ZoneOffset.UTC)
36
+
37
+ public fun format(instant: Instant): String = formatter.format(instant)
38
+
39
+ /** Tolerant on the way in: a peer that omitted the fractional part is still understood. */
40
+ public fun parse(text: String): Instant = Instant.parse(text)
41
+ }
42
+
43
+ /** A health store the SDK can link. One connection per source per device. */
44
+ @Serializable
45
+ public enum class Source {
46
+ @SerialName("health")
47
+ HEALTH,
48
+ /**
49
+ * Samsung Health, through the terra-android-samsung add-on. Connect, disconnect, permissions
50
+ * and diagnostics take it; reads, writes and change streams are Health Connect's.
51
+ *
52
+ * Available on android only.
53
+ */
54
+ @SerialName("samsungHealth")
55
+ SAMSUNG_HEALTH,
56
+ }
57
+
58
+ /** The unit permissions are asked for and changes are reported against. */
59
+ @Serializable
60
+ public enum class DataCategory {
61
+ @SerialName("activity")
62
+ ACTIVITY,
63
+ @SerialName("body")
64
+ BODY,
65
+ @SerialName("daily")
66
+ DAILY,
67
+ @SerialName("sleep")
68
+ SLEEP,
69
+ @SerialName("nutrition")
70
+ NUTRITION,
71
+ /**
72
+ * Read-only on both platforms: menstruation.flow reads it and neither SDK has a write route
73
+ * for it.
74
+ */
75
+ @SerialName("menstruation")
76
+ MENSTRUATION,
77
+ /**
78
+ * HealthKit's characteristics; Health Connect has no counterpart.
79
+ *
80
+ * Available on ios only.
81
+ */
82
+ @SerialName("athlete")
83
+ ATHLETE,
84
+ }
85
+
86
+ @Serializable
87
+ public enum class PermissionStatus {
88
+ @SerialName("granted")
89
+ GRANTED,
90
+ @SerialName("denied")
91
+ DENIED,
92
+ @SerialName("notDetermined")
93
+ NOT_DETERMINED,
94
+ /**
95
+ * A read grant HealthKit will not report. Not an error: it is the documented answer for reads
96
+ * on iOS.
97
+ */
98
+ @SerialName("notDisclosed")
99
+ NOT_DISCLOSED,
100
+ @SerialName("unsupported")
101
+ UNSUPPORTED,
102
+ /**
103
+ * Android answers unsupported where Apple would answer unavailable.
104
+ *
105
+ * Available on ios only.
106
+ */
107
+ @SerialName("unavailable")
108
+ UNAVAILABLE,
109
+ }
110
+
111
+ @Serializable
112
+ public enum class MotionContext {
113
+ @SerialName("unknown")
114
+ UNKNOWN,
115
+ @SerialName("sedentary")
116
+ SEDENTARY,
117
+ @SerialName("active")
118
+ ACTIVE,
119
+ }
120
+
121
+ /**
122
+ * On both platforms, wire names strip HKQuantityTypeIdentifierDietary from HealthKit
123
+ * identifiers and lowercase the first letter. Units: kcal for energyConsumed; grams for
124
+ * protein, carbohydrates, the four fats, sugar and fiber; milligrams for everything else,
125
+ * never micrograms.
126
+ */
127
+ @Serializable
128
+ public enum class Nutrient {
129
+ @SerialName("energyConsumed")
130
+ ENERGY_CONSUMED,
131
+ @SerialName("protein")
132
+ PROTEIN,
133
+ @SerialName("carbohydrates")
134
+ CARBOHYDRATES,
135
+ @SerialName("fatTotal")
136
+ FAT_TOTAL,
137
+ @SerialName("fatSaturated")
138
+ FAT_SATURATED,
139
+ @SerialName("fatMonounsaturated")
140
+ FAT_MONOUNSATURATED,
141
+ @SerialName("fatPolyunsaturated")
142
+ FAT_POLYUNSATURATED,
143
+ @SerialName("sugar")
144
+ SUGAR,
145
+ @SerialName("fiber")
146
+ FIBER,
147
+ @SerialName("cholesterol")
148
+ CHOLESTEROL,
149
+ @SerialName("sodium")
150
+ SODIUM,
151
+ @SerialName("potassium")
152
+ POTASSIUM,
153
+ @SerialName("calcium")
154
+ CALCIUM,
155
+ @SerialName("iron")
156
+ IRON,
157
+ @SerialName("magnesium")
158
+ MAGNESIUM,
159
+ @SerialName("zinc")
160
+ ZINC,
161
+ @SerialName("phosphorus")
162
+ PHOSPHORUS,
163
+ @SerialName("iodine")
164
+ IODINE,
165
+ @SerialName("manganese")
166
+ MANGANESE,
167
+ @SerialName("molybdenum")
168
+ MOLYBDENUM,
169
+ @SerialName("selenium")
170
+ SELENIUM,
171
+ @SerialName("copper")
172
+ COPPER,
173
+ @SerialName("chromium")
174
+ CHROMIUM,
175
+ @SerialName("chloride")
176
+ CHLORIDE,
177
+ @SerialName("caffeine")
178
+ CAFFEINE,
179
+ @SerialName("vitaminA")
180
+ VITAMIN_A,
181
+ @SerialName("vitaminC")
182
+ VITAMIN_C,
183
+ @SerialName("vitaminD")
184
+ VITAMIN_D,
185
+ @SerialName("vitaminE")
186
+ VITAMIN_E,
187
+ @SerialName("vitaminK")
188
+ VITAMIN_K,
189
+ @SerialName("vitaminB6")
190
+ VITAMIN_B6,
191
+ @SerialName("vitaminB12")
192
+ VITAMIN_B12,
193
+ @SerialName("thiamin")
194
+ THIAMIN,
195
+ @SerialName("riboflavin")
196
+ RIBOFLAVIN,
197
+ @SerialName("niacin")
198
+ NIACIN,
199
+ @SerialName("folate")
200
+ FOLATE,
201
+ @SerialName("biotin")
202
+ BIOTIN,
203
+ @SerialName("pantothenicAcid")
204
+ PANTOTHENIC_ACID,
205
+ }
206
+
207
+ /**
208
+ * Which meal a quantity was logged against. unknown is the store's explicit answer, not an
209
+ * absence: HealthKit has no meal type at all, so every iOS quantity is unknown.
210
+ */
211
+ @Serializable
212
+ public enum class MealType {
213
+ @SerialName("breakfast")
214
+ BREAKFAST,
215
+ @SerialName("lunch")
216
+ LUNCH,
217
+ @SerialName("dinner")
218
+ DINNER,
219
+ @SerialName("snack")
220
+ SNACK,
221
+ @SerialName("unknown")
222
+ UNKNOWN,
223
+ }
224
+
225
+ /** How heavy a logged day's flow was. */
226
+ @Serializable
227
+ public enum class MenstruationFlow {
228
+ @SerialName("unspecified")
229
+ UNSPECIFIED,
230
+ @SerialName("light")
231
+ LIGHT,
232
+ @SerialName("medium")
233
+ MEDIUM,
234
+ @SerialName("heavy")
235
+ HEAVY,
236
+ /**
237
+ * noFlow avoids ambiguity with Optional.none. Health Connect has no constant for it, so
238
+ * Android never produces it.
239
+ */
240
+ @SerialName("none")
241
+ NO_FLOW,
242
+ }
243
+
244
+ /** Available on ios only. */
245
+ @Serializable
246
+ public enum class BiologicalSex {
247
+ @SerialName("female")
248
+ FEMALE,
249
+ @SerialName("male")
250
+ MALE,
251
+ @SerialName("other")
252
+ OTHER,
253
+ /**
254
+ * The characteristic exists and holds no value, or reading it failed. The store's explicit
255
+ * unknown.
256
+ */
257
+ @SerialName("notSet")
258
+ NOT_SET,
259
+ }
260
+
261
+ /**
262
+ * A move-time user's daily totals are minutes rather than active energy.
263
+ *
264
+ * Available on ios only.
265
+ */
266
+ @Serializable
267
+ public enum class ActivityMoveMode {
268
+ @SerialName("activeEnergy")
269
+ ACTIVE_ENERGY,
270
+ @SerialName("appleMoveTime")
271
+ APPLE_MOVE_TIME,
272
+ }
273
+
274
+ /**
275
+ * Why background delivery is restricted. Android discloses which; Apple reports the state
276
+ * without a reason.
277
+ *
278
+ * Available on android only.
279
+ */
280
+ @Serializable
281
+ public enum class BackgroundRestrictionReason {
282
+ @SerialName("oemRestricted")
283
+ OEM_RESTRICTED,
284
+ @SerialName("backgroundReadDenied")
285
+ BACKGROUND_READ_DENIED,
286
+ @SerialName("healthConnectFeatureUnavailable")
287
+ HEALTH_CONNECT_FEATURE_UNAVAILABLE,
288
+ @SerialName("storeFeatureUnavailable")
289
+ STORE_FEATURE_UNAVAILABLE,
290
+ @SerialName("ticksNotRunning")
291
+ TICKS_NOT_RUNNING,
292
+ }
293
+
294
+ @Serializable
295
+ public enum class DiagnosticsReason {
296
+ @SerialName("uploadFailed")
297
+ UPLOAD_FAILED,
298
+ @SerialName("backfillAbandoned")
299
+ BACKFILL_ABANDONED,
300
+ @SerialName("backgroundObservationUnavailable")
301
+ BACKGROUND_OBSERVATION_UNAVAILABLE,
302
+ @SerialName("backgroundRestricted")
303
+ BACKGROUND_RESTRICTED,
304
+ @SerialName("backgroundRefreshUnscheduled")
305
+ BACKGROUND_REFRESH_UNSCHEDULED,
306
+ @SerialName("quiet")
307
+ QUIET,
308
+ @SerialName("requested")
309
+ REQUESTED,
310
+ }
311
+
312
+ @Serializable
313
+ public enum class DeviceKeyRevokeOutcome {
314
+ @SerialName("revoked")
315
+ REVOKED,
316
+ @SerialName("alreadyRevoked")
317
+ ALREADY_REVOKED,
318
+ @SerialName("routeAbsent")
319
+ ROUTE_ABSENT,
320
+ }
321
+
322
+ /**
323
+ * The redacted error name an event carries. Deliberately not TerraErrorCode: an event names
324
+ * the failure without the detail bag, because a support report leaves the device.
325
+ */
326
+ @Serializable
327
+ public enum class FailureCode {
328
+ @SerialName("healthDataUnavailable")
329
+ HEALTH_DATA_UNAVAILABLE,
330
+ @SerialName("notConnected")
331
+ NOT_CONNECTED,
332
+ @SerialName("tokenUnavailable")
333
+ TOKEN_UNAVAILABLE,
334
+ @SerialName("tokenRejected")
335
+ TOKEN_REJECTED,
336
+ @SerialName("tokenProviderFailed")
337
+ TOKEN_PROVIDER_FAILED,
338
+ @SerialName("offline")
339
+ OFFLINE,
340
+ @SerialName("timedOut")
341
+ TIMED_OUT,
342
+ @SerialName("serverError")
343
+ SERVER_ERROR,
344
+ @SerialName("transport")
345
+ TRANSPORT,
346
+ @SerialName("malformedResponse")
347
+ MALFORMED_RESPONSE,
348
+ @SerialName("userLimitReached")
349
+ USER_LIMIT_REACHED,
350
+ @SerialName("upgradeRequired")
351
+ UPGRADE_REQUIRED,
352
+ @SerialName("platform")
353
+ PLATFORM,
354
+ @SerialName("deviceKeyUnavailable")
355
+ DEVICE_KEY_UNAVAILABLE,
356
+ @SerialName("signatureRejected")
357
+ SIGNATURE_REJECTED,
358
+ @SerialName("linkRevoked")
359
+ LINK_REVOKED,
360
+ @SerialName("linkConflict")
361
+ LINK_CONFLICT,
362
+ @SerialName("clockSkewed")
363
+ CLOCK_SKEWED,
364
+ @SerialName("devIDMismatch")
365
+ DEV_IDMISMATCH,
366
+ @SerialName("syncAlreadyRunning")
367
+ SYNC_ALREADY_RUNNING,
368
+ @SerialName("linkAlreadyRunning")
369
+ LINK_ALREADY_RUNNING,
370
+ @SerialName("storeLocked")
371
+ STORE_LOCKED,
372
+ @SerialName("storeUnreadable")
373
+ STORE_UNREADABLE,
374
+ @SerialName("deadlineExceeded")
375
+ DEADLINE_EXCEEDED,
376
+ @SerialName("permissionDenied")
377
+ PERMISSION_DENIED,
378
+ @SerialName("authorizationNotDetermined")
379
+ AUTHORIZATION_NOT_DETERMINED,
380
+ @SerialName("sampleNotFound")
381
+ SAMPLE_NOT_FOUND,
382
+ @SerialName("rollbackIncomplete")
383
+ ROLLBACK_INCOMPLETE,
384
+ @SerialName("distanceNotAttributable")
385
+ DISTANCE_NOT_ATTRIBUTABLE,
386
+ @SerialName("bloodPressureIncomplete")
387
+ BLOOD_PRESSURE_INCOMPLETE,
388
+ @SerialName("authorizationUnavailableInExtension")
389
+ AUTHORIZATION_UNAVAILABLE_IN_EXTENSION,
390
+ @SerialName("routeAwaitingConverter")
391
+ ROUTE_AWAITING_CONVERTER,
392
+ /** Available on android only. */
393
+ @SerialName("readQuotaExceeded")
394
+ READ_QUOTA_EXCEEDED,
395
+ /**
396
+ * Apple's FailureCode carries it; Android's does not, because there is no Android
397
+ * planned-workout model.
398
+ *
399
+ * Available on ios only.
400
+ */
401
+ @SerialName("plannedWorkoutUnnamed")
402
+ PLANNED_WORKOUT_UNNAMED,
403
+ }
404
+
405
+ /**
406
+ * Whether Terra's plans can be put on the person's Apple Watch. unsupported before iOS 17 or
407
+ * where WorkoutKit cannot schedule.
408
+ *
409
+ * Available on ios only.
410
+ */
411
+ @Serializable
412
+ public enum class WorkoutSchedulingStatus {
413
+ @SerialName("unsupported")
414
+ UNSUPPORTED,
415
+ @SerialName("notDetermined")
416
+ NOT_DETERMINED,
417
+ @SerialName("denied")
418
+ DENIED,
419
+ @SerialName("authorized")
420
+ AUTHORIZED,
421
+ }
422
+
423
+ /**
424
+ * distance* are metres, *EnergyBurned kilocalories, flightsClimbed a count, and
425
+ * appleExerciseTime minutes.
426
+ */
427
+ @Serializable
428
+ public enum class DayTotalMetric {
429
+ @SerialName("distanceWalkingRunning")
430
+ DISTANCE_WALKING_RUNNING,
431
+ /** Health Connect does not split distance by activity, so only Apple ever answers it. */
432
+ @SerialName("distanceCycling")
433
+ DISTANCE_CYCLING,
434
+ @SerialName("distanceSwimming")
435
+ DISTANCE_SWIMMING,
436
+ @SerialName("distanceWheelchair")
437
+ DISTANCE_WHEELCHAIR,
438
+ @SerialName("activeEnergyBurned")
439
+ ACTIVE_ENERGY_BURNED,
440
+ @SerialName("basalEnergyBurned")
441
+ BASAL_ENERGY_BURNED,
442
+ @SerialName("flightsClimbed")
443
+ FLIGHTS_CLIMBED,
444
+ /**
445
+ * The exercise ring, in minutes. Health Connect has no such figure: summing session durations
446
+ * is a different number.
447
+ *
448
+ * Available on ios only.
449
+ */
450
+ @SerialName("appleExerciseTime")
451
+ APPLE_EXERCISE_TIME,
452
+ }
453
+
454
+ /** activeEnergy and basalEnergy are kilocalories, distance metres, floorsClimbed a count. */
455
+ @Serializable
456
+ public enum class IntradayMetric {
457
+ @SerialName("activeEnergy")
458
+ ACTIVE_ENERGY,
459
+ /**
460
+ * Health Connect has no basal energy record; its basal metabolic rate is a body measurement
461
+ * and is not this.
462
+ *
463
+ * Available on ios only.
464
+ */
465
+ @SerialName("basalEnergy")
466
+ BASAL_ENERGY,
467
+ @SerialName("distance")
468
+ DISTANCE,
469
+ @SerialName("floorsClimbed")
470
+ FLOORS_CLIMBED,
471
+ }
472
+
473
+ /** speed is metres per second, power watts, cadence pedal revolutions per minute. */
474
+ @Serializable
475
+ public enum class WorkoutIntensityMetric {
476
+ @SerialName("speed")
477
+ SPEED,
478
+ @SerialName("power")
479
+ POWER,
480
+ @SerialName("cadence")
481
+ CADENCE,
482
+ }
483
+
484
+ /**
485
+ * The body composition figure a measurement carries. weight and leanBodyMass are kilograms,
486
+ * height centimetres, bodyFatPercentage a fraction in 0..1, bmi dimensionless.
487
+ */
488
+ @Serializable
489
+ public enum class BodyMetric {
490
+ @SerialName("weight")
491
+ WEIGHT,
492
+ @SerialName("height")
493
+ HEIGHT,
494
+ @SerialName("bodyFatPercentage")
495
+ BODY_FAT_PERCENTAGE,
496
+ @SerialName("leanBodyMass")
497
+ LEAN_BODY_MASS,
498
+ /**
499
+ * Health Connect has no BMI record.
500
+ *
501
+ * Available on ios only.
502
+ */
503
+ @SerialName("bmi")
504
+ BMI,
505
+ }
506
+
507
+ /** The unit the writing app chose. Never converted on the device. */
508
+ @Serializable
509
+ public enum class BloodGlucoseUnit {
510
+ @SerialName("mg/dL")
511
+ MILLIGRAMS_PER_DECILITRE,
512
+ @SerialName("mmol/L")
513
+ MILLIMOLES_PER_LITRE,
514
+ }
515
+
516
+ /** unknown is the store saying nothing about the meal, distinct from absent. */
517
+ @Serializable
518
+ public enum class GlucoseMealTime {
519
+ @SerialName("preprandial")
520
+ PREPRANDIAL,
521
+ @SerialName("postprandial")
522
+ POSTPRANDIAL,
523
+ @SerialName("unknown")
524
+ UNKNOWN,
525
+ }
526
+
527
+ /** interstitial is a continuous monitor. */
528
+ @Serializable
529
+ public enum class GlucoseSpecimen {
530
+ @SerialName("capillary")
531
+ CAPILLARY,
532
+ @SerialName("interstitial")
533
+ INTERSTITIAL,
534
+ @SerialName("plasma")
535
+ PLASMA,
536
+ @SerialName("serum")
537
+ SERUM,
538
+ @SerialName("tears")
539
+ TEARS,
540
+ @SerialName("wholeBlood")
541
+ WHOLE_BLOOD,
542
+ @SerialName("unknown")
543
+ UNKNOWN,
544
+ }
545
+
546
+ /**
547
+ * body and basal are absolute; wrist and skin are deltas from a baseline and routinely
548
+ * negative.
549
+ */
550
+ @Serializable
551
+ public enum class BodyTemperatureMetric {
552
+ @SerialName("body")
553
+ BODY,
554
+ @SerialName("basal")
555
+ BASAL,
556
+ /**
557
+ * HealthKit's sleeping wrist temperature. Health Connect has no such record.
558
+ *
559
+ * Available on ios only.
560
+ */
561
+ @SerialName("wrist")
562
+ WRIST,
563
+ @SerialName("skin")
564
+ SKIN,
565
+ }
566
+
567
+ /** HealthKit records SDNN only and Health Connect RMSSD only; they are never one series. */
568
+ @Serializable
569
+ public enum class HeartRateVariabilityMetric {
570
+ @SerialName("sdnn")
571
+ SDNN,
572
+ @SerialName("rmssd")
573
+ RMSSD,
574
+ }
575
+
576
+ @Serializable
577
+ public enum class VO2MaxTestType {
578
+ @SerialName("maxExercise")
579
+ MAX_EXERCISE,
580
+ @SerialName("predictedSubMaxExercise")
581
+ PREDICTED_SUB_MAX_EXERCISE,
582
+ @SerialName("predictedNonExercise")
583
+ PREDICTED_NON_EXERCISE,
584
+ }
585
+
586
+ @Serializable
587
+ public enum class MenstrualEventKind {
588
+ @SerialName("intermenstrualBleeding")
589
+ INTERMENSTRUAL_BLEEDING,
590
+ @SerialName("ovulationTest")
591
+ OVULATION_TEST,
592
+ @SerialName("cervicalMucus")
593
+ CERVICAL_MUCUS,
594
+ }
595
+
596
+ /**
597
+ * The person a connect is for. A stored link is restored only for the person it was made for;
598
+ * anybody else gets a fresh link. Never sent to Terra as identity.
599
+ */
600
+ @Serializable
601
+ @OptIn(ExperimentalSerializationApi::class)
602
+ @JsonClassDiscriminator("kind")
603
+ public sealed interface EndUser {
604
+ /** The app's id for this person: the same value its backend puts in the token. */
605
+ @Serializable
606
+ @SerialName("reference")
607
+ public data class Reference(public val id: String) : EndUser
608
+ /** No reference: one link per install. */
609
+ @Serializable
610
+ @SerialName("anonymous")
611
+ public data object Anonymous : EndUser
612
+ }
613
+
614
+ /** A half-open window [start, end). Resolved against the device's calendar natively. */
615
+ @Serializable
616
+ @OptIn(ExperimentalSerializationApi::class)
617
+ @JsonClassDiscriminator("kind")
618
+ public sealed interface TimeRange {
619
+ @Serializable
620
+ @SerialName("lastHours")
621
+ public data class LastHours(public val hours: Int) : TimeRange
622
+ @Serializable
623
+ @SerialName("lastDays")
624
+ public data class LastDays(public val days: Int) : TimeRange
625
+ @Serializable
626
+ @SerialName("today")
627
+ public data object Today : TimeRange
628
+ @Serializable
629
+ @SerialName("between")
630
+ public data class Between(public val start: String, public val end: String) : TimeRange
631
+ }
632
+
633
+ @Serializable
634
+ @OptIn(ExperimentalSerializationApi::class)
635
+ @JsonClassDiscriminator("kind")
636
+ public sealed interface SleepStage {
637
+ @Serializable
638
+ @SerialName("inBed")
639
+ public data object InBed : SleepStage
640
+ @Serializable
641
+ @SerialName("awake")
642
+ public data object Awake : SleepStage
643
+ @Serializable
644
+ @SerialName("asleep")
645
+ public data object Asleep : SleepStage
646
+ @Serializable
647
+ @SerialName("light")
648
+ public data object Light : SleepStage
649
+ @Serializable
650
+ @SerialName("deep")
651
+ public data object Deep : SleepStage
652
+ @Serializable
653
+ @SerialName("rem")
654
+ public data object Rem : SleepStage
655
+ /**
656
+ * A stage the store reported that neither SDK maps. The raw value is carried so an app can log
657
+ * it.
658
+ */
659
+ @Serializable
660
+ @SerialName("unknown")
661
+ public data class Unknown(public val raw: String) : SleepStage
662
+ }
663
+
664
+ @Serializable
665
+ @OptIn(ExperimentalSerializationApi::class)
666
+ @JsonClassDiscriminator("kind")
667
+ public sealed interface WorkoutActivity {
668
+ @Serializable
669
+ @SerialName("running")
670
+ public data object Running : WorkoutActivity
671
+ @Serializable
672
+ @SerialName("walking")
673
+ public data object Walking : WorkoutActivity
674
+ @Serializable
675
+ @SerialName("cycling")
676
+ public data object Cycling : WorkoutActivity
677
+ @Serializable
678
+ @SerialName("swimming")
679
+ public data object Swimming : WorkoutActivity
680
+ @Serializable
681
+ @SerialName("strengthTraining")
682
+ public data object StrengthTraining : WorkoutActivity
683
+ @Serializable
684
+ @SerialName("other")
685
+ public data class Other(public val label: String) : WorkoutActivity
686
+ }
687
+
688
+ /**
689
+ * What the SDK believes about delivery right now. Wire spelling matches DiagnosticsWire.state
690
+ * and Apple's DiagnosticsState Encodable.
691
+ */
692
+ @Serializable
693
+ @OptIn(ExperimentalSerializationApi::class)
694
+ @JsonClassDiscriminator("state")
695
+ public sealed interface DiagnosticsState {
696
+ @Serializable
697
+ @SerialName("healthy")
698
+ public data object Healthy : DiagnosticsState
699
+ @Serializable
700
+ @SerialName("quiet")
701
+ public data class Quiet(public val since: String) : DiagnosticsState
702
+ @Serializable
703
+ @SerialName("backgroundRestricted")
704
+ public data class BackgroundRestricted(public val reason: BackgroundRestrictionReason? = null) : DiagnosticsState
705
+ @Serializable
706
+ @SerialName("backgroundRefreshUnscheduled")
707
+ public data object BackgroundRefreshUnscheduled : DiagnosticsState
708
+ @Serializable
709
+ @SerialName("pendingRetry")
710
+ public data object PendingRetry : DiagnosticsState
711
+ @Serializable
712
+ @SerialName("linkRevoked")
713
+ public data object LinkRevoked : DiagnosticsState
714
+ /**
715
+ * Apple reports the mismatch as a state. Android raises dev_id_mismatch and has no state for
716
+ * it.
717
+ *
718
+ * Available on ios only.
719
+ */
720
+ @Serializable
721
+ @SerialName("devIDMismatch")
722
+ public data object DevIDMismatch : DiagnosticsState
723
+ }
724
+
725
+ /**
726
+ * What a subscription delivers. A stream can fail or finish, and without saying so the
727
+ * framework layer has to invent a convention for both - two of those, one per wrapper, is a
728
+ * contract nobody wrote down.
729
+ */
730
+ @Serializable
731
+ @OptIn(ExperimentalSerializationApi::class)
732
+ @JsonClassDiscriminator("kind")
733
+ public sealed interface StreamMessage {
734
+ @Serializable
735
+ @SerialName("data")
736
+ public data class Data(public val element: JsonObject) : StreamMessage
737
+ /** The stream failed. The subscription is over; the id will deliver nothing more. */
738
+ @Serializable
739
+ @SerialName("error")
740
+ public data class Error(public val error: TerraErrorPayload) : StreamMessage
741
+ /** The stream ended on its own. The host should drop the subscription rather than unsubscribe. */
742
+ @Serializable
743
+ @SerialName("complete")
744
+ public data object Complete : StreamMessage
745
+ }
746
+
747
+ /**
748
+ * What a BodyReading measured, with the unit fixed by the variant. Blood glucose alone keeps
749
+ * the writer's unit.
750
+ */
751
+ @Serializable
752
+ @OptIn(ExperimentalSerializationApi::class)
753
+ @JsonClassDiscriminator("type")
754
+ public sealed interface BodyReadingKind {
755
+ @Serializable
756
+ @SerialName("measurement")
757
+ public data class Measurement(public val metric: BodyMetric, public val value: Double) : BodyReadingKind
758
+ /** Millimetres of mercury, both halves of one reading. */
759
+ @Serializable
760
+ @SerialName("bloodPressure")
761
+ public data class BloodPressure(public val systolic: Double, public val diastolic: Double) : BodyReadingKind
762
+ @Serializable
763
+ @SerialName("bloodGlucose")
764
+ public data class BloodGlucose(public val value: Double, public val unit: BloodGlucoseUnit, public val mealTime: GlucoseMealTime? = null, public val specimen: GlucoseSpecimen? = null) : BodyReadingKind
765
+ /** A fraction in 0..1, never a number out of a hundred. */
766
+ @Serializable
767
+ @SerialName("oxygenSaturation")
768
+ public data class OxygenSaturation(public val fraction: Double) : BodyReadingKind
769
+ @Serializable
770
+ @SerialName("temperature")
771
+ public data class Temperature(public val metric: BodyTemperatureMetric, public val celsius: Double) : BodyReadingKind
772
+ @Serializable
773
+ @SerialName("heartRateVariability")
774
+ public data class HeartRateVariability(public val metric: HeartRateVariabilityMetric, public val milliseconds: Double) : BodyReadingKind
775
+ @Serializable
776
+ @SerialName("respiratoryRate")
777
+ public data class RespiratoryRate(public val breathsPerMinute: Double) : BodyReadingKind
778
+ /** Millilitres of oxygen per kilogram per minute. */
779
+ @Serializable
780
+ @SerialName("vo2Max")
781
+ public data class Vo2Max(public val millilitresPerKilogramMinute: Double, public val testType: VO2MaxTestType? = null) : BodyReadingKind
782
+ }
783
+
784
+ /**
785
+ * Apple's store is part of the OS, so it is there or the device cannot have it; Health Connect
786
+ * is an app a person can lack.
787
+ */
788
+ @Serializable
789
+ @OptIn(ExperimentalSerializationApi::class)
790
+ @JsonClassDiscriminator("kind")
791
+ public sealed interface StoreAvailability {
792
+ @Serializable
793
+ @SerialName("available")
794
+ public data object Available : StoreAvailability
795
+ /**
796
+ * No HealthKit on this device: an iPad before iPadOS 17, or a Mac.
797
+ *
798
+ * Available on ios only.
799
+ */
800
+ @Serializable
801
+ @SerialName("unsupportedDevice")
802
+ public data object UnsupportedDevice : StoreAvailability
803
+ /**
804
+ * No Health Connect on Android 13 or below, or no Samsung Health. A Play Store link fixes the
805
+ * first.
806
+ *
807
+ * Available on android only.
808
+ */
809
+ @Serializable
810
+ @SerialName("providerAppMissing")
811
+ public data object ProviderAppMissing : StoreAvailability
812
+ /** Available on android only. */
813
+ @Serializable
814
+ @SerialName("providerAppTooOld")
815
+ public data class ProviderAppTooOld(public val installed: String) : StoreAvailability
816
+ /**
817
+ * The source's add-on artifact is not in the app.
818
+ *
819
+ * Available on android only.
820
+ */
821
+ @Serializable
822
+ @SerialName("moduleMissing")
823
+ public data object ModuleMissing : StoreAvailability
824
+ /**
825
+ * The store's partner policy covers none of the record types. Which ones is in the native
826
+ * report.
827
+ *
828
+ * Available on android only.
829
+ */
830
+ @Serializable
831
+ @SerialName("partnerPolicyMissing")
832
+ public data object PartnerPolicyMissing : StoreAvailability
833
+ /**
834
+ * The provider app lacks a feature the store needs. Which one is in the native report.
835
+ *
836
+ * Available on android only.
837
+ */
838
+ @Serializable
839
+ @SerialName("featureUnavailable")
840
+ public data object FeatureUnavailable : StoreAvailability
841
+ }
842
+
843
+ public object DataCategorySetSerializer : KSerializer<List<DataCategory>> {
844
+ private val list = ListSerializer(DataCategory.serializer())
845
+ override val descriptor: SerialDescriptor = list.descriptor
846
+
847
+ override fun serialize(encoder: Encoder, value: List<DataCategory>): Unit = list.serialize(encoder, canonical(value))
848
+
849
+ override fun deserialize(decoder: Decoder): List<DataCategory> = canonical(list.deserialize(decoder))
850
+
851
+ private fun canonical(value: List<DataCategory>): List<DataCategory> =
852
+ value.distinct().sortedBy { DataCategory.serializer().descriptor.getElementName(it.ordinal) }
853
+ }
854
+
855
+ /** Who recorded a sample. The only stable handle an app has for filtering by app or device. */
856
+ @Serializable
857
+ public data class SampleSource(
858
+ public val name: String,
859
+ public val bundleId: String,
860
+ public val productType: String? = null,
861
+ public val deviceType: String? = null,
862
+ )
863
+
864
+ /**
865
+ * A link record. A value, not a handle: Apple's Connection carries sync and disconnect
866
+ * methods, and an object with behaviour cannot cross the bridge, so those are ops on the
867
+ * client.
868
+ */
869
+ @Serializable
870
+ public data class Connection(
871
+ public val source: Source,
872
+ public val userId: String,
873
+ /**
874
+ * Android's StoredConnection carries the store-side id. Apple's Connection does not.
875
+ *
876
+ * Available on android only.
877
+ */
878
+ public val providerUserId: String? = null,
879
+ )
880
+
881
+ @Serializable
882
+ public data class HeartRateSample(
883
+ public val id: String,
884
+ public val time: String,
885
+ public val beatsPerMinute: Double,
886
+ public val source: SampleSource,
887
+ public val motionContext: MotionContext? = null,
888
+ public val userEntered: Boolean,
889
+ public val timeZone: String? = null,
890
+ )
891
+
892
+ /**
893
+ * A step total over an interval. Apple derives the id from the source and start; Android
894
+ * carries a RecordId when it has one, so the id is optional on the wire.
895
+ */
896
+ @Serializable
897
+ public data class StepCount(
898
+ public val id: String? = null,
899
+ public val start: String,
900
+ public val end: String,
901
+ public val steps: Int,
902
+ public val source: SampleSource,
903
+ public val userEntered: Boolean,
904
+ public val timeZone: String? = null,
905
+ )
906
+
907
+ @Serializable
908
+ public data class SleepSegment(
909
+ public val id: String,
910
+ public val start: String,
911
+ public val end: String,
912
+ public val stage: SleepStage,
913
+ public val source: SampleSource,
914
+ public val userEntered: Boolean,
915
+ public val timeZone: String? = null,
916
+ )
917
+
918
+ /**
919
+ * indoor is optional because Health Connect does not always record it; Apple always has an
920
+ * answer.
921
+ */
922
+ @Serializable
923
+ public data class Workout(
924
+ public val id: String,
925
+ public val start: String,
926
+ public val end: String,
927
+ public val activity: WorkoutActivity,
928
+ public val activityTypeCode: Int,
929
+ public val indoor: Boolean? = null,
930
+ public val activeEnergyKilocalories: Double? = null,
931
+ public val distanceMeters: Double? = null,
932
+ public val source: SampleSource,
933
+ public val userEntered: Boolean,
934
+ public val timeZone: String? = null,
935
+ /**
936
+ * ExerciseSessionRecord.title on Android; HKMetadataKeyWorkoutBrandName on Apple, which has no
937
+ * title field.
938
+ */
939
+ public val title: String? = null,
940
+ )
941
+
942
+ /** Quantities of one meal share foodCorrelationId. */
943
+ @Serializable
944
+ public data class DietaryQuantity(
945
+ public val id: String,
946
+ public val nutrient: Nutrient,
947
+ public val value: Double,
948
+ public val start: String,
949
+ public val end: String,
950
+ public val mealType: MealType,
951
+ public val name: String? = null,
952
+ /**
953
+ * HealthKit's food correlation, absent for a loose quantity. Always set on Android, where it
954
+ * is the NutritionRecord's id - the id nutrition.delete takes for a meal this app logged.
955
+ */
956
+ public val foodCorrelationId: String? = null,
957
+ public val source: SampleSource,
958
+ public val userEntered: Boolean,
959
+ public val timeZone: String? = null,
960
+ )
961
+
962
+ /** start and end are the local midnights of that day in timeZone. */
963
+ @Serializable
964
+ public data class MenstruationFlowDay(
965
+ public val id: String,
966
+ public val start: String,
967
+ public val end: String,
968
+ public val flow: MenstruationFlow,
969
+ public val cycleStart: Boolean,
970
+ public val source: SampleSource,
971
+ public val userEntered: Boolean,
972
+ public val timeZone: String? = null,
973
+ )
974
+
975
+ /** Available on ios only. */
976
+ @Serializable
977
+ public data class AthleteProfile(
978
+ public val biologicalSex: BiologicalSex? = null,
979
+ /** A calendar day, as HealthKit stores it, never an instant. */
980
+ public val dateOfBirth: String? = null,
981
+ public val wheelchairUse: Boolean? = null,
982
+ public val activityMoveMode: ActivityMoveMode? = null,
983
+ )
984
+
985
+ /** A day whose data changed. Carries no health value by construction. */
986
+ @Serializable
987
+ public data class HealthChange(
988
+ public val category: DataCategory,
989
+ public val day: String,
990
+ )
991
+
992
+ @Serializable
993
+ public data class WorkoutScope(
994
+ public val activity: WorkoutActivity,
995
+ public val energy: Boolean,
996
+ public val distance: Boolean,
997
+ )
998
+
999
+ /**
1000
+ * Lists rather than sets: JSON has no set, so the category lists are marked `set` and every
1001
+ * generated codec de-duplicates and sorts them, so two orderings compare equal.
1002
+ */
1003
+ @Serializable
1004
+ public data class HealthAccess(
1005
+ @Serializable(with = DataCategorySetSerializer::class) public val read: List<DataCategory>,
1006
+ @Serializable(with = DataCategorySetSerializer::class) public val write: List<DataCategory>,
1007
+ public val workouts: List<WorkoutScope>,
1008
+ )
1009
+
1010
+ @Serializable
1011
+ public data class HeartRateEntry(
1012
+ public val time: String,
1013
+ public val beatsPerMinute: Double,
1014
+ public val recordId: String? = null,
1015
+ )
1016
+
1017
+ @Serializable
1018
+ public data class StepEntry(
1019
+ public val start: String,
1020
+ public val end: String,
1021
+ public val steps: Int,
1022
+ public val recordId: String? = null,
1023
+ )
1024
+
1025
+ @Serializable
1026
+ public data class SleepEntry(
1027
+ public val start: String,
1028
+ public val end: String,
1029
+ public val stage: SleepStage,
1030
+ public val recordId: String? = null,
1031
+ )
1032
+
1033
+ @Serializable
1034
+ public data class WorkoutEntry(
1035
+ public val start: String,
1036
+ public val end: String,
1037
+ public val activity: WorkoutActivity,
1038
+ public val totalEnergyKilocalories: Double? = null,
1039
+ public val totalDistanceMeters: Double? = null,
1040
+ public val recordId: String? = null,
1041
+ )
1042
+
1043
+ @Serializable
1044
+ public data class BodyEntry(
1045
+ public val time: String,
1046
+ public val bodyMassKilograms: Double? = null,
1047
+ public val bodyFatPercent: Double? = null,
1048
+ public val bodyMassIndex: Double? = null,
1049
+ public val heightMeters: Double? = null,
1050
+ public val leanBodyMassKilograms: Double? = null,
1051
+ public val bodyTemperatureCelsius: Double? = null,
1052
+ public val oxygenSaturationPercent: Double? = null,
1053
+ public val bloodGlucoseMilligramsPerDeciliter: Double? = null,
1054
+ public val bloodPressureSystolicMillimetersOfMercury: Double? = null,
1055
+ public val bloodPressureDiastolicMillimetersOfMercury: Double? = null,
1056
+ public val recordId: String? = null,
1057
+ )
1058
+
1059
+ /**
1060
+ * Every field optional and every unit in the name, matching NutritionEntry.Nutrients on both
1061
+ * platforms field for field.
1062
+ */
1063
+ @Serializable
1064
+ public data class Nutrients(
1065
+ public val energyKilocalories: Double? = null,
1066
+ public val proteinGrams: Double? = null,
1067
+ public val carbohydratesGrams: Double? = null,
1068
+ public val fiberGrams: Double? = null,
1069
+ public val sugarGrams: Double? = null,
1070
+ public val fatTotalGrams: Double? = null,
1071
+ public val fatSaturatedGrams: Double? = null,
1072
+ public val fatMonounsaturatedGrams: Double? = null,
1073
+ public val fatPolyunsaturatedGrams: Double? = null,
1074
+ public val cholesterolMilligrams: Double? = null,
1075
+ public val sodiumMilligrams: Double? = null,
1076
+ public val potassiumMilligrams: Double? = null,
1077
+ public val calciumMilligrams: Double? = null,
1078
+ public val ironMilligrams: Double? = null,
1079
+ public val magnesiumMilligrams: Double? = null,
1080
+ public val zincMilligrams: Double? = null,
1081
+ public val waterLiters: Double? = null,
1082
+ public val caffeineMilligrams: Double? = null,
1083
+ public val vitaminAMicrograms: Double? = null,
1084
+ public val vitaminCMilligrams: Double? = null,
1085
+ public val vitaminDMicrograms: Double? = null,
1086
+ public val vitaminEMilligrams: Double? = null,
1087
+ public val vitaminKMicrograms: Double? = null,
1088
+ public val vitaminB6Milligrams: Double? = null,
1089
+ public val vitaminB12Micrograms: Double? = null,
1090
+ public val folateMicrograms: Double? = null,
1091
+ public val thiaminMilligrams: Double? = null,
1092
+ public val riboflavinMilligrams: Double? = null,
1093
+ public val niacinMilligrams: Double? = null,
1094
+ public val biotinMicrograms: Double? = null,
1095
+ public val pantothenicAcidMilligrams: Double? = null,
1096
+ public val phosphorusMilligrams: Double? = null,
1097
+ public val iodineMicrograms: Double? = null,
1098
+ public val chromiumMicrograms: Double? = null,
1099
+ public val copperMilligrams: Double? = null,
1100
+ public val manganeseMilligrams: Double? = null,
1101
+ public val molybdenumMicrograms: Double? = null,
1102
+ public val seleniumMicrograms: Double? = null,
1103
+ public val chlorideMilligrams: Double? = null,
1104
+ )
1105
+
1106
+ @Serializable
1107
+ public data class NutritionEntry(
1108
+ public val start: String,
1109
+ public val end: String,
1110
+ public val name: String? = null,
1111
+ public val nutrients: Nutrients,
1112
+ public val recordId: String? = null,
1113
+ )
1114
+
1115
+ /**
1116
+ * An error carried as a value rather than thrown, inside a sync result. The same shape the
1117
+ * bridge rejects a promise with.
1118
+ */
1119
+ @Serializable
1120
+ public data class TerraErrorPayload(
1121
+ public val code: String,
1122
+ public val retryable: Boolean,
1123
+ public val message: String,
1124
+ public val source: Source? = null,
1125
+ public val details: JsonObject? = null,
1126
+ )
1127
+
1128
+ /** Available on ios only. */
1129
+ @Serializable
1130
+ public data class PlannedWorkout(
1131
+ public val id: String? = null,
1132
+ public val plannedOn: String? = null,
1133
+ public val activity: WorkoutActivity? = null,
1134
+ public val title: String? = null,
1135
+ public val completedAt: String? = null,
1136
+ )
1137
+
1138
+ /**
1139
+ * The flat object both SDKs already emit: `at`, `event`, and whatever keys that kind carries.
1140
+ * Carried through unchanged rather than reshaped, because reshaping it would be a hand-written
1141
+ * second contract on each platform that no vector could pin - and the encoding it would be
1142
+ * translating is one DiagnosticsWire and Apple's Encodable already agree on, and that
1143
+ * EventPrivacyTest already guards against carrying a health value.
1144
+ */
1145
+ public typealias TerraEvent = JsonObject
1146
+
1147
+ /**
1148
+ * The redacted report, carried as the wire object DiagnosticsWire.report and Apple's
1149
+ * SupportReport.json already produce.
1150
+ */
1151
+ @Serializable
1152
+ public data class SupportReport(
1153
+ public val sdkVersion: String,
1154
+ public val generatedAt: String,
1155
+ public val state: DiagnosticsState,
1156
+ public val lastDelivery: String? = null,
1157
+ public val isConnected: Boolean,
1158
+ public val requestedCategories: List<String>,
1159
+ public val requestedWrites: List<String>,
1160
+ public val requestedWorkouts: List<String>,
1161
+ public val recentEvents: List<TerraEvent>,
1162
+ )
1163
+
1164
+ /**
1165
+ * What the JS side needs to know about the native client it is attaching to. bootstrapped
1166
+ * false is a host setup bug, and the wrapper says so with the exact line to add.
1167
+ */
1168
+ @Serializable
1169
+ public data class BootstrapState(
1170
+ public val bootstrapped: Boolean,
1171
+ public val devId: String? = null,
1172
+ public val platform: String,
1173
+ public val sdkVersion: String,
1174
+ public val backgroundRegistered: Boolean,
1175
+ )
1176
+
1177
+ /**
1178
+ * The broker asking JS for a link token. Answered by token.resolve or token.reject with the
1179
+ * same requestId.
1180
+ */
1181
+ @Serializable
1182
+ public data class TokenRequest(
1183
+ public val requestId: String,
1184
+ )
1185
+
1186
+ /** No request fields, or no response value. */
1187
+ @Serializable
1188
+ public class Empty
1189
+
1190
+ @Serializable
1191
+ public data class SourceRequest(
1192
+ public val source: Source? = null,
1193
+ )
1194
+
1195
+ @Serializable
1196
+ public data class RangeRequest(
1197
+ public val range: TimeRange,
1198
+ )
1199
+
1200
+ @Serializable
1201
+ public data class CategoryRequest(
1202
+ public val category: DataCategory,
1203
+ public val source: Source? = null,
1204
+ )
1205
+
1206
+ @Serializable
1207
+ public data class RecordIdRequest(
1208
+ public val id: String,
1209
+ )
1210
+
1211
+ @Serializable
1212
+ public data class ConnectRequest(
1213
+ public val source: Source? = null,
1214
+ public val endUser: EndUser,
1215
+ /**
1216
+ * A grant already in hand, from a QR code or a deep link. Absent means the token provider is
1217
+ * asked.
1218
+ */
1219
+ public val token: String? = null,
1220
+ )
1221
+
1222
+ @Serializable
1223
+ public data class PermissionRequest(
1224
+ @Serializable(with = DataCategorySetSerializer::class) public val read: List<DataCategory>,
1225
+ @Serializable(with = DataCategorySetSerializer::class) public val write: List<DataCategory>,
1226
+ public val workouts: List<WorkoutScope>,
1227
+ public val source: Source? = null,
1228
+ )
1229
+
1230
+ /**
1231
+ * What the sheet granted. Android answers with the access this call obtained; HealthKit will
1232
+ * not report read grants, so Apple answers nothing at all.
1233
+ */
1234
+ @Serializable
1235
+ public data class PermissionGrant(
1236
+ /** Available on android only. */
1237
+ public val granted: HealthAccess? = null,
1238
+ )
1239
+
1240
+ @Serializable
1241
+ public data class TokenResolveRequest(
1242
+ public val requestId: String,
1243
+ public val token: String,
1244
+ )
1245
+
1246
+ @Serializable
1247
+ public data class TokenRejectRequest(
1248
+ public val requestId: String,
1249
+ public val message: String,
1250
+ )
1251
+
1252
+ @Serializable
1253
+ public data class TokenProviderRequest(
1254
+ public val present: Boolean,
1255
+ public val timeoutMs: Int,
1256
+ )
1257
+
1258
+ /** Available on ios only. */
1259
+ @Serializable
1260
+ public data class MarkCompleteRequest(
1261
+ public val id: String? = null,
1262
+ public val at: String? = null,
1263
+ )
1264
+
1265
+ @Serializable
1266
+ public data class BoolResult(
1267
+ public val value: Boolean,
1268
+ )
1269
+
1270
+ @Serializable
1271
+ public data class StatusResult(
1272
+ public val status: PermissionStatus,
1273
+ )
1274
+
1275
+ /** Available on android only. */
1276
+ @Serializable
1277
+ public data class StatusesResult(
1278
+ public val statuses: Map<DataCategory, PermissionStatus>,
1279
+ )
1280
+
1281
+ @Serializable
1282
+ public data class RecordIdList(
1283
+ public val ids: List<String>,
1284
+ )
1285
+
1286
+ @Serializable
1287
+ public data class ConnectionList(
1288
+ public val connections: List<Connection>,
1289
+ )
1290
+
1291
+ @Serializable
1292
+ public data class HeartRateList(
1293
+ public val samples: List<HeartRateSample>,
1294
+ )
1295
+
1296
+ @Serializable
1297
+ public data class StepCountList(
1298
+ public val samples: List<StepCount>,
1299
+ )
1300
+
1301
+ @Serializable
1302
+ public data class SleepSegmentList(
1303
+ public val samples: List<SleepSegment>,
1304
+ )
1305
+
1306
+ @Serializable
1307
+ public data class WorkoutList(
1308
+ public val samples: List<Workout>,
1309
+ )
1310
+
1311
+ @Serializable
1312
+ public data class DietaryQuantityList(
1313
+ public val samples: List<DietaryQuantity>,
1314
+ )
1315
+
1316
+ @Serializable
1317
+ public data class MenstruationFlowDayList(
1318
+ public val samples: List<MenstruationFlowDay>,
1319
+ )
1320
+
1321
+ /** A cycle event logged at an instant. */
1322
+ @Serializable
1323
+ public data class MenstrualEvent(
1324
+ public val id: String,
1325
+ public val kind: MenstrualEventKind,
1326
+ public val time: String,
1327
+ /**
1328
+ * ovulationTest: negative, positive, high, indeterminate or luteinizingHormoneSurge.
1329
+ * cervicalMucus: dry, sticky, creamy, watery, eggWhite or unusual. Absent for
1330
+ * intermenstrualBleeding, which is a flag.
1331
+ */
1332
+ public val value: String? = null,
1333
+ /**
1334
+ * The store's own record type, passed through: OvulationTestRecord on Android,
1335
+ * HKCategoryTypeIdentifierOvulationTestResult on Apple.
1336
+ */
1337
+ public val storeIdentifier: String,
1338
+ public val source: SampleSource,
1339
+ public val userEntered: Boolean,
1340
+ public val timeZone: String? = null,
1341
+ )
1342
+
1343
+ @Serializable
1344
+ public data class MenstrualEventList(
1345
+ public val samples: List<MenstrualEvent>,
1346
+ )
1347
+
1348
+ /** Available on ios only. */
1349
+ @Serializable
1350
+ public data class AthleteProfileResult(
1351
+ public val profile: AthleteProfile? = null,
1352
+ )
1353
+
1354
+ /** Available on ios only. */
1355
+ @Serializable
1356
+ public data class PlannedWorkoutList(
1357
+ public val workouts: List<PlannedWorkout>? = null,
1358
+ )
1359
+
1360
+ /**
1361
+ * Once authorized, every sync run keeps the Watch schedule in step with Terra.
1362
+ *
1363
+ * Available on ios only.
1364
+ */
1365
+ @Serializable
1366
+ public data class WorkoutScheduling(
1367
+ public val status: WorkoutSchedulingStatus? = null,
1368
+ )
1369
+
1370
+ @Serializable
1371
+ public data class LastDeliveryResult(
1372
+ public val at: String? = null,
1373
+ )
1374
+
1375
+ @Serializable
1376
+ public data class HeartRateEntryList(
1377
+ public val entries: List<HeartRateEntry>,
1378
+ )
1379
+
1380
+ @Serializable
1381
+ public data class BodyEntryList(
1382
+ public val entries: List<BodyEntry>,
1383
+ )
1384
+
1385
+ @Serializable
1386
+ public data class StepEntryList(
1387
+ public val entries: List<StepEntry>,
1388
+ )
1389
+
1390
+ @Serializable
1391
+ public data class SleepEntryList(
1392
+ public val entries: List<SleepEntry>,
1393
+ )
1394
+
1395
+ @Serializable
1396
+ public data class WorkoutEntryList(
1397
+ public val entries: List<WorkoutEntry>,
1398
+ )
1399
+
1400
+ @Serializable
1401
+ public data class NutritionEntryList(
1402
+ public val entries: List<NutritionEntry>,
1403
+ )
1404
+
1405
+ /**
1406
+ * The store's own total for one local day, from its statistics engine. start and end are that
1407
+ * day's midnights.
1408
+ */
1409
+ @Serializable
1410
+ public data class DayTotal(
1411
+ public val metric: DayTotalMetric,
1412
+ public val start: String,
1413
+ public val end: String,
1414
+ public val value: Double,
1415
+ public val unit: String,
1416
+ public val timeZone: String? = null,
1417
+ )
1418
+
1419
+ /**
1420
+ * One record a day total is made of, as the store holds it. A record crossing midnight is
1421
+ * whole.
1422
+ */
1423
+ @Serializable
1424
+ public data class IntradaySample(
1425
+ public val id: String,
1426
+ public val metric: IntradayMetric,
1427
+ public val start: String,
1428
+ public val end: String,
1429
+ public val value: Double,
1430
+ public val source: SampleSource,
1431
+ public val userEntered: Boolean,
1432
+ public val timeZone: String? = null,
1433
+ )
1434
+
1435
+ /** The store's own resting heart rate for a day, never derived from heart rate readings. */
1436
+ @Serializable
1437
+ public data class RestingHeartRateSample(
1438
+ public val id: String,
1439
+ public val start: String,
1440
+ public val end: String,
1441
+ public val beatsPerMinute: Double,
1442
+ public val source: SampleSource,
1443
+ public val userEntered: Boolean,
1444
+ public val timeZone: String? = null,
1445
+ )
1446
+
1447
+ /** A point reading has start equal to end; skin and wrist temperature span a stretch. */
1448
+ @Serializable
1449
+ public data class BodyReading(
1450
+ public val id: String,
1451
+ public val kind: BodyReadingKind,
1452
+ public val start: String,
1453
+ public val end: String,
1454
+ public val source: SampleSource,
1455
+ public val userEntered: Boolean,
1456
+ public val timeZone: String? = null,
1457
+ )
1458
+
1459
+ @Serializable
1460
+ public data class RoutePoint(
1461
+ public val time: String,
1462
+ public val latitude: Double,
1463
+ public val longitude: Double,
1464
+ )
1465
+
1466
+ /**
1467
+ * The GPS track a workout left, thinned to one point a second and at most 5,000 points. start
1468
+ * and end are the first and last point.
1469
+ */
1470
+ @Serializable
1471
+ public data class WorkoutRoute(
1472
+ public val id: String,
1473
+ public val workoutId: String,
1474
+ public val start: String,
1475
+ public val end: String,
1476
+ public val points: List<RoutePoint>,
1477
+ public val source: SampleSource,
1478
+ public val timeZone: String? = null,
1479
+ )
1480
+
1481
+ /** One speed, power or cadence reading. Android's are instants, so start equals end there. */
1482
+ @Serializable
1483
+ public data class WorkoutIntensitySample(
1484
+ public val id: String,
1485
+ public val metric: WorkoutIntensityMetric,
1486
+ /**
1487
+ * Set on Apple, where HealthKit stores a reading inside its workout. Health Connect stores
1488
+ * them free-standing, so Android leaves it absent rather than guessing by time.
1489
+ */
1490
+ public val workoutId: String? = null,
1491
+ public val start: String,
1492
+ public val end: String,
1493
+ public val value: Double,
1494
+ public val source: SampleSource,
1495
+ public val userEntered: Boolean,
1496
+ public val timeZone: String? = null,
1497
+ )
1498
+
1499
+ /** One drink, in millilitres. */
1500
+ @Serializable
1501
+ public data class HydrationSample(
1502
+ public val id: String,
1503
+ public val start: String,
1504
+ public val end: String,
1505
+ public val millilitres: Double,
1506
+ public val source: SampleSource,
1507
+ public val userEntered: Boolean,
1508
+ public val timeZone: String? = null,
1509
+ )
1510
+
1511
+ @Serializable
1512
+ public data class DayTotalList(
1513
+ public val totals: List<DayTotal>,
1514
+ )
1515
+
1516
+ @Serializable
1517
+ public data class IntradaySampleList(
1518
+ public val samples: List<IntradaySample>,
1519
+ )
1520
+
1521
+ @Serializable
1522
+ public data class RestingHeartRateList(
1523
+ public val samples: List<RestingHeartRateSample>,
1524
+ )
1525
+
1526
+ @Serializable
1527
+ public data class BodyReadingList(
1528
+ public val samples: List<BodyReading>,
1529
+ )
1530
+
1531
+ @Serializable
1532
+ public data class WorkoutRouteList(
1533
+ public val routes: List<WorkoutRoute>,
1534
+ )
1535
+
1536
+ @Serializable
1537
+ public data class WorkoutIntensityList(
1538
+ public val samples: List<WorkoutIntensitySample>,
1539
+ )
1540
+
1541
+ @Serializable
1542
+ public data class HydrationList(
1543
+ public val samples: List<HydrationSample>,
1544
+ )
1545
+
1546
+ @Serializable
1547
+ public data class AvailabilityResult(
1548
+ public val availability: StoreAvailability,
1549
+ )
1550
+
1551
+ public object TerraEventEnvelope {
1552
+ public fun validate(value: TerraEvent) {
1553
+ if ((value["at"] as? JsonPrimitive)?.isString != true) {
1554
+ throw SerializationException("TerraEvent.at is not a string")
1555
+ }
1556
+ if ((value["event"] as? JsonPrimitive)?.isString != true) {
1557
+ throw SerializationException("TerraEvent.event is not a string")
1558
+ }
1559
+ }
1560
+ }
1561
+
1562
+ public object SupportReportEnvelope {
1563
+ public fun validate(value: SupportReport) {
1564
+ for (level0 in value.recentEvents) {
1565
+ TerraEventEnvelope.validate(level0)
1566
+ }
1567
+ }
1568
+ }
1569
+