@tryterra/react-native 0.0.0-stage → 2.1.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.
- package/LICENSE +21 -0
- package/README.md +111 -2
- package/TerraReactNative.podspec +48 -0
- package/android/build.gradle +87 -0
- package/android/src/bridgeCore/kotlin/README.md +1 -0
- package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/BridgeBootstrap.kt +133 -0
- package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/BridgeHost.kt +32 -0
- package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/Conversions.kt +468 -0
- package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/LauncherSlots.kt +41 -0
- package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/Rejections.kt +150 -0
- package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/StreamRegistry.kt +77 -0
- package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/TerraBridge.kt +86 -0
- package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/TerraBridgeOpsImpl.kt +258 -0
- package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/TerraBridgeStreamsImpl.kt +52 -0
- package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/TokenBroker.kt +198 -0
- package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/generated/BridgeErrors.kt +217 -0
- package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/generated/BridgeOps.kt +493 -0
- package/android/src/bridgeCore/kotlin/co/tryterra/sdk/bridge/generated/BridgeTypes.kt +897 -0
- package/android/src/healthConnectOnly/kotlin/co/tryterra/sdk/reactnative/TerraStores.kt +11 -0
- package/android/src/main/AndroidManifest.xml +24 -0
- package/android/src/main/java/co/tryterra/sdk/reactnative/TerraBridgeModule.kt +96 -0
- package/android/src/main/java/co/tryterra/sdk/reactnative/TerraReactNativePackage.kt +26 -0
- package/android/src/main/java/co/tryterra/sdk/reactnative/TerraStartup.kt +46 -0
- package/android/src/samsung/kotlin/co/tryterra/sdk/reactnative/TerraStores.kt +13 -0
- package/docs/availability.md +246 -0
- package/frameworks/TerraSDK.xcframework/Info.plist +48 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Info.plist +0 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.abi.json +81513 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.package.swiftinterface +2150 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.private.swiftinterface +2150 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios.swiftinterface +2127 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/PrivacyInfo.xcprivacy +96 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64/TerraSDK.framework/TerraSDK +0 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64/dSYMs/TerraSDK.framework.dSYM/Contents/Info.plist +20 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/DWARF/TerraSDK +0 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/Relocations/aarch64/TerraSDK.yml +6473 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Info.plist +0 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.abi.json +81513 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.package.swiftinterface +2150 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.private.swiftinterface +2150 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/arm64-apple-ios-simulator.swiftinterface +2127 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.abi.json +81513 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.package.swiftinterface +2150 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.private.swiftinterface +2150 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/Modules/TerraSDK.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +2127 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/PrivacyInfo.xcprivacy +96 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/TerraSDK +0 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/TerraSDK.framework/_CodeSignature/CodeResources +223 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/TerraSDK.framework.dSYM/Contents/Info.plist +20 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/DWARF/TerraSDK +0 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/Relocations/aarch64/TerraSDK.yml +6474 -0
- package/frameworks/TerraSDK.xcframework/ios-arm64_x86_64-simulator/dSYMs/TerraSDK.framework.dSYM/Contents/Resources/Relocations/x86_64/TerraSDK.yml +6392 -0
- package/ios/TerraBridgeCore/BridgeBootstrap.swift +89 -0
- package/ios/TerraBridgeCore/BridgeHost.swift +13 -0
- package/ios/TerraBridgeCore/Conversions.swift +467 -0
- package/ios/TerraBridgeCore/Generated/BridgeErrors.swift +179 -0
- package/ios/TerraBridgeCore/Generated/BridgeOps.swift +795 -0
- package/ios/TerraBridgeCore/Generated/BridgeTypes.swift +1317 -0
- package/ios/TerraBridgeCore/Locked.swift +15 -0
- package/ios/TerraBridgeCore/README.md +1 -0
- package/ios/TerraBridgeCore/Rejections.swift +130 -0
- package/ios/TerraBridgeCore/RuntimeAttachment.swift +60 -0
- package/ios/TerraBridgeCore/StreamRegistry.swift +59 -0
- package/ios/TerraBridgeCore/TerraBridge.swift +122 -0
- package/ios/TerraBridgeCore/TerraBridgeOpsImpl.swift +254 -0
- package/ios/TerraBridgeCore/TerraBridgeStreamsImpl.swift +60 -0
- package/ios/TerraBridgeCore/TokenBroker.swift +147 -0
- package/ios/TerraBridgeModule.mm +79 -0
- package/ios/TerraBridgeModuleImpl.swift +49 -0
- package/ios/TerraReactNative.swift +19 -0
- package/lib/EndUser.d.ts +12 -0
- package/lib/EndUser.js +13 -0
- package/lib/NativeTerraBridge.d.ts +23 -0
- package/lib/NativeTerraBridge.js +13 -0
- package/lib/Terra.d.ts +154 -0
- package/lib/Terra.js +280 -0
- package/lib/TerraError.d.ts +42 -0
- package/lib/TerraError.js +95 -0
- package/lib/createTerra.d.ts +8 -0
- package/lib/createTerra.js +19 -0
- package/lib/generated/client.d.ts +92 -0
- package/lib/generated/client.js +196 -0
- package/lib/generated/codecs.d.ts +135 -0
- package/lib/generated/codecs.js +1358 -0
- package/lib/generated/errors.d.ts +13 -0
- package/lib/generated/errors.js +68 -0
- package/lib/generated/ops.d.ts +13 -0
- package/lib/generated/ops.js +137 -0
- package/lib/generated/streams.d.ts +23 -0
- package/lib/generated/streams.js +58 -0
- package/lib/generated/types.d.ts +481 -0
- package/lib/generated/types.js +92 -0
- package/lib/index.d.ts +29 -0
- package/lib/index.js +55 -0
- package/package.json +71 -4
- package/src/EndUser.ts +15 -0
- package/src/NativeTerraBridge.ts +27 -0
- package/src/Terra.ts +462 -0
- package/src/TerraError.ts +116 -0
- package/src/createTerra.ts +18 -0
- package/src/generated/client.ts +243 -0
- package/src/generated/codecs.ts +1287 -0
- package/src/generated/errors.ts +113 -0
- package/src/generated/ops.ts +197 -0
- package/src/generated/streams.ts +74 -0
- package/src/generated/types.ts +667 -0
- package/src/index.ts +52 -0
|
@@ -0,0 +1,1317 @@
|
|
|
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
|
+
import Foundation
|
|
5
|
+
|
|
6
|
+
/// The one spelling of an instant on the wire: UTC, and always exactly three fractional digits.
|
|
7
|
+
///
|
|
8
|
+
/// `.iso8601` is not it. `ISO8601DateFormatter` without `.withFractionalSeconds` drops the
|
|
9
|
+
/// sub-second part, and HealthKit stores sub-second, so a round trip through the bridge would
|
|
10
|
+
/// silently move every sample to the nearest whole second. Three digits rather than however many
|
|
11
|
+
/// the source had, so that the same instant produces the same bytes in Swift, Kotlin and
|
|
12
|
+
/// JavaScript - which is what lets a vector be compared rather than interpreted.
|
|
13
|
+
public enum BridgeInstant {
|
|
14
|
+
/// `ISO8601DateFormatter` is not `Sendable`, and building one per call is not free on a read
|
|
15
|
+
/// of a month of samples. One pair behind a lock is the cheap end of correct here.
|
|
16
|
+
private final class Formatters: @unchecked Sendable {
|
|
17
|
+
let lock = NSLock()
|
|
18
|
+
let withFraction = ISO8601DateFormatter()
|
|
19
|
+
let withoutFraction = ISO8601DateFormatter()
|
|
20
|
+
|
|
21
|
+
init() {
|
|
22
|
+
withFraction.formatOptions = [.withInternetDateTime, .withFractionalSeconds]
|
|
23
|
+
withFraction.timeZone = TimeZone(secondsFromGMT: 0)
|
|
24
|
+
withoutFraction.formatOptions = [.withInternetDateTime]
|
|
25
|
+
withoutFraction.timeZone = TimeZone(secondsFromGMT: 0)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
private static let formatters = Formatters()
|
|
30
|
+
|
|
31
|
+
public static func format(_ date: Date) -> String {
|
|
32
|
+
formatters.lock.lock()
|
|
33
|
+
defer { formatters.lock.unlock() }
|
|
34
|
+
return formatters.withFraction.string(from: date)
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/// Tolerant on the way in: a peer that omitted the fractional part is still understood.
|
|
38
|
+
public static func parse(_ text: String) -> Date? {
|
|
39
|
+
formatters.lock.lock()
|
|
40
|
+
defer { formatters.lock.unlock() }
|
|
41
|
+
return formatters.withFraction.date(from: text) ?? formatters.withoutFraction.date(from: text)
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/// A JSON value the bridge carries without interpreting: an error's detail bag, an event's payload.
|
|
46
|
+
///
|
|
47
|
+
/// The SDKs already encode those shapes, and re-describing them here would be a second opinion
|
|
48
|
+
/// about a spelling `DiagnosticsWire` and Apple's `Encodable` already agree on.
|
|
49
|
+
public struct BridgeJSON: Codable, Equatable, Sendable {
|
|
50
|
+
public let storage: [String: BridgeValue]
|
|
51
|
+
public init(_ storage: [String: BridgeValue]) { self.storage = storage }
|
|
52
|
+
public init(from decoder: any Decoder) throws {
|
|
53
|
+
storage = try decoder.singleValueContainer().decode([String: BridgeValue].self)
|
|
54
|
+
}
|
|
55
|
+
public func encode(to encoder: any Encoder) throws {
|
|
56
|
+
var container = encoder.singleValueContainer()
|
|
57
|
+
try container.encode(storage)
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/// `indirect` because the cases hold `BridgeValue`: without it the enum has no finite size and
|
|
62
|
+
/// the file does not compile.
|
|
63
|
+
public indirect enum BridgeValue: Codable, Equatable, Sendable {
|
|
64
|
+
case string(String)
|
|
65
|
+
case number(Double)
|
|
66
|
+
case bool(Bool)
|
|
67
|
+
case array([BridgeValue])
|
|
68
|
+
case object([String: BridgeValue])
|
|
69
|
+
case null
|
|
70
|
+
|
|
71
|
+
public init(from decoder: any Decoder) throws {
|
|
72
|
+
let container = try decoder.singleValueContainer()
|
|
73
|
+
if container.decodeNil() { self = .null; return }
|
|
74
|
+
if let value = try? container.decode(Bool.self) { self = .bool(value); return }
|
|
75
|
+
if let value = try? container.decode(Double.self) { self = .number(value); return }
|
|
76
|
+
if let value = try? container.decode(String.self) { self = .string(value); return }
|
|
77
|
+
if let value = try? container.decode([BridgeValue].self) { self = .array(value); return }
|
|
78
|
+
self = .object(try container.decode([String: BridgeValue].self))
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
public func encode(to encoder: any Encoder) throws {
|
|
82
|
+
var container = encoder.singleValueContainer()
|
|
83
|
+
switch self {
|
|
84
|
+
case .string(let value): try container.encode(value)
|
|
85
|
+
case .number(let value): try container.encode(value)
|
|
86
|
+
case .bool(let value): try container.encode(value)
|
|
87
|
+
case .array(let value): try container.encode(value)
|
|
88
|
+
case .object(let value): try container.encode(value)
|
|
89
|
+
case .null: try container.encodeNil()
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/// A list of enum cases that is a set on the wire: de-duplicated and sorted by wire spelling
|
|
95
|
+
/// whenever it is stored, decoded or encoded, as the Kotlin and TypeScript codecs do.
|
|
96
|
+
@propertyWrapper
|
|
97
|
+
public struct CaseSet<Element: RawRepresentable & Codable & Hashable & Sendable>: Codable, Equatable, Sendable
|
|
98
|
+
where Element.RawValue == String {
|
|
99
|
+
private var storage: [Element]
|
|
100
|
+
|
|
101
|
+
public var wrappedValue: [Element] {
|
|
102
|
+
get { storage }
|
|
103
|
+
set { storage = Self.canonical(newValue) }
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
public init(wrappedValue: [Element]) { storage = Self.canonical(wrappedValue) }
|
|
107
|
+
|
|
108
|
+
public init(from decoder: any Decoder) throws {
|
|
109
|
+
storage = Self.canonical(try decoder.singleValueContainer().decode([Element].self))
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
public func encode(to encoder: any Encoder) throws {
|
|
113
|
+
var container = encoder.singleValueContainer()
|
|
114
|
+
try container.encode(storage)
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
private static func canonical(_ value: [Element]) -> [Element] {
|
|
118
|
+
Array(Set(value)).sorted { $0.rawValue < $1.rawValue }
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/// A health store the SDK can link. One connection per source per device.
|
|
123
|
+
public enum Source: String, Codable, Sendable, CaseIterable {
|
|
124
|
+
case health = "health"
|
|
125
|
+
/// Samsung Health, through the terra-android-samsung add-on. Connect, disconnect, permissions
|
|
126
|
+
/// and diagnostics take it; reads, writes and change streams are Health Connect's.
|
|
127
|
+
///
|
|
128
|
+
/// Available on android only.
|
|
129
|
+
case samsungHealth = "samsungHealth"
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/// The unit permissions are asked for and changes are reported against.
|
|
133
|
+
public enum DataCategory: String, Codable, Sendable, CaseIterable {
|
|
134
|
+
case activity = "activity"
|
|
135
|
+
case body = "body"
|
|
136
|
+
case daily = "daily"
|
|
137
|
+
case sleep = "sleep"
|
|
138
|
+
case nutrition = "nutrition"
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
public enum PermissionStatus: String, Codable, Sendable, CaseIterable {
|
|
142
|
+
case granted = "granted"
|
|
143
|
+
case denied = "denied"
|
|
144
|
+
case notDetermined = "notDetermined"
|
|
145
|
+
/// A read grant HealthKit will not report. Not an error: it is the documented answer for reads
|
|
146
|
+
/// on iOS.
|
|
147
|
+
case notDisclosed = "notDisclosed"
|
|
148
|
+
case unsupported = "unsupported"
|
|
149
|
+
/// Android answers unsupported where Apple would answer unavailable.
|
|
150
|
+
///
|
|
151
|
+
/// Available on ios only.
|
|
152
|
+
case unavailable = "unavailable"
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
public enum MotionContext: String, Codable, Sendable, CaseIterable {
|
|
156
|
+
case unknown = "unknown"
|
|
157
|
+
case sedentary = "sedentary"
|
|
158
|
+
case active = "active"
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/// Why background delivery is restricted. Android discloses which; Apple reports the state
|
|
162
|
+
/// without a reason.
|
|
163
|
+
///
|
|
164
|
+
/// Available on android only.
|
|
165
|
+
public enum BackgroundRestrictionReason: String, Codable, Sendable, CaseIterable {
|
|
166
|
+
case oemRestricted = "oemRestricted"
|
|
167
|
+
case backgroundReadDenied = "backgroundReadDenied"
|
|
168
|
+
case healthConnectFeatureUnavailable = "healthConnectFeatureUnavailable"
|
|
169
|
+
case storeFeatureUnavailable = "storeFeatureUnavailable"
|
|
170
|
+
case ticksNotRunning = "ticksNotRunning"
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
public enum DiagnosticsReason: String, Codable, Sendable, CaseIterable {
|
|
174
|
+
case uploadFailed = "uploadFailed"
|
|
175
|
+
case backfillAbandoned = "backfillAbandoned"
|
|
176
|
+
case backgroundObservationUnavailable = "backgroundObservationUnavailable"
|
|
177
|
+
case backgroundRestricted = "backgroundRestricted"
|
|
178
|
+
case backgroundRefreshUnscheduled = "backgroundRefreshUnscheduled"
|
|
179
|
+
case quiet = "quiet"
|
|
180
|
+
case requested = "requested"
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
public enum DeviceKeyRevokeOutcome: String, Codable, Sendable, CaseIterable {
|
|
184
|
+
case revoked = "revoked"
|
|
185
|
+
case alreadyRevoked = "alreadyRevoked"
|
|
186
|
+
case routeAbsent = "routeAbsent"
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/// The redacted error name an event carries. Deliberately not TerraErrorCode: an event names
|
|
190
|
+
/// the failure without the detail bag, because a support report leaves the device.
|
|
191
|
+
public enum FailureCode: String, Codable, Sendable, CaseIterable {
|
|
192
|
+
case healthDataUnavailable = "healthDataUnavailable"
|
|
193
|
+
case notConnected = "notConnected"
|
|
194
|
+
case tokenUnavailable = "tokenUnavailable"
|
|
195
|
+
case tokenRejected = "tokenRejected"
|
|
196
|
+
case tokenProviderFailed = "tokenProviderFailed"
|
|
197
|
+
case offline = "offline"
|
|
198
|
+
case timedOut = "timedOut"
|
|
199
|
+
case serverError = "serverError"
|
|
200
|
+
case transport = "transport"
|
|
201
|
+
case malformedResponse = "malformedResponse"
|
|
202
|
+
case userLimitReached = "userLimitReached"
|
|
203
|
+
case upgradeRequired = "upgradeRequired"
|
|
204
|
+
case platform = "platform"
|
|
205
|
+
case deviceKeyUnavailable = "deviceKeyUnavailable"
|
|
206
|
+
case signatureRejected = "signatureRejected"
|
|
207
|
+
case linkRevoked = "linkRevoked"
|
|
208
|
+
case linkConflict = "linkConflict"
|
|
209
|
+
case clockSkewed = "clockSkewed"
|
|
210
|
+
case devIDMismatch = "devIDMismatch"
|
|
211
|
+
case syncAlreadyRunning = "syncAlreadyRunning"
|
|
212
|
+
case linkAlreadyRunning = "linkAlreadyRunning"
|
|
213
|
+
case storeLocked = "storeLocked"
|
|
214
|
+
case storeUnreadable = "storeUnreadable"
|
|
215
|
+
case deadlineExceeded = "deadlineExceeded"
|
|
216
|
+
case permissionDenied = "permissionDenied"
|
|
217
|
+
case authorizationNotDetermined = "authorizationNotDetermined"
|
|
218
|
+
case sampleNotFound = "sampleNotFound"
|
|
219
|
+
case rollbackIncomplete = "rollbackIncomplete"
|
|
220
|
+
case distanceNotAttributable = "distanceNotAttributable"
|
|
221
|
+
case bloodPressureIncomplete = "bloodPressureIncomplete"
|
|
222
|
+
case authorizationUnavailableInExtension = "authorizationUnavailableInExtension"
|
|
223
|
+
case routeAwaitingConverter = "routeAwaitingConverter"
|
|
224
|
+
/// Available on android only.
|
|
225
|
+
case readQuotaExceeded = "readQuotaExceeded"
|
|
226
|
+
/// Apple's FailureCode carries it; Android's does not, because there is no Android
|
|
227
|
+
/// planned-workout model.
|
|
228
|
+
///
|
|
229
|
+
/// Available on ios only.
|
|
230
|
+
case plannedWorkoutUnnamed = "plannedWorkoutUnnamed"
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
/// Whether Terra's plans can be put on the person's Apple Watch. unsupported before iOS 17 or
|
|
234
|
+
/// where WorkoutKit cannot schedule.
|
|
235
|
+
///
|
|
236
|
+
/// Available on ios only.
|
|
237
|
+
public enum WorkoutSchedulingStatus: String, Codable, Sendable, CaseIterable {
|
|
238
|
+
case unsupported = "unsupported"
|
|
239
|
+
case notDetermined = "notDetermined"
|
|
240
|
+
case denied = "denied"
|
|
241
|
+
case authorized = "authorized"
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/// A `CodingKey` over a plain string, for the dictionary-key conformances below.
|
|
245
|
+
public struct StringCodingKey: CodingKey {
|
|
246
|
+
public let stringValue: String
|
|
247
|
+
public var intValue: Int? { nil }
|
|
248
|
+
public init(_ value: String) { stringValue = value }
|
|
249
|
+
public init?(stringValue: String) { self.stringValue = stringValue }
|
|
250
|
+
public init?(intValue: Int) { return nil }
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/// So that a `[DataCategory: T]` encodes as a JSON object rather than an alternating array.
|
|
254
|
+
extension DataCategory: CodingKeyRepresentable {
|
|
255
|
+
public var codingKey: any CodingKey { StringCodingKey(rawValue) }
|
|
256
|
+
public init?<T: CodingKey>(codingKey: T) {
|
|
257
|
+
self.init(rawValue: codingKey.stringValue)
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
/// The person a connect is for. A stored link is restored only for the person it was made for;
|
|
262
|
+
/// anybody else gets a fresh link. Never sent to Terra as identity.
|
|
263
|
+
public enum EndUser: Codable, Equatable, Sendable {
|
|
264
|
+
case reference(id: String)
|
|
265
|
+
case anonymous
|
|
266
|
+
|
|
267
|
+
private enum CodingKeys: String, CodingKey {
|
|
268
|
+
case kind
|
|
269
|
+
case id
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
public init(from decoder: any Decoder) throws {
|
|
273
|
+
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
274
|
+
let tag = try container.decode(String.self, forKey: .kind)
|
|
275
|
+
switch tag {
|
|
276
|
+
case "reference":
|
|
277
|
+
let id = try container.decode(String.self, forKey: .id)
|
|
278
|
+
self = .reference(id: id)
|
|
279
|
+
case "anonymous":
|
|
280
|
+
self = .anonymous
|
|
281
|
+
default:
|
|
282
|
+
throw DecodingError.dataCorruptedError(forKey: .kind, in: container, debugDescription: "unknown EndUser \(tag)")
|
|
283
|
+
}
|
|
284
|
+
}
|
|
285
|
+
|
|
286
|
+
public func encode(to encoder: any Encoder) throws {
|
|
287
|
+
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
288
|
+
switch self {
|
|
289
|
+
case .reference(let id):
|
|
290
|
+
try container.encode("reference", forKey: .kind)
|
|
291
|
+
try container.encode(id, forKey: .id)
|
|
292
|
+
case .anonymous:
|
|
293
|
+
try container.encode("anonymous", forKey: .kind)
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/// A half-open window [start, end). Resolved against the device's calendar natively.
|
|
299
|
+
public enum TimeRange: Codable, Equatable, Sendable {
|
|
300
|
+
case lastHours(hours: Int)
|
|
301
|
+
case lastDays(days: Int)
|
|
302
|
+
case today
|
|
303
|
+
case between(start: String, end: String)
|
|
304
|
+
|
|
305
|
+
private enum CodingKeys: String, CodingKey {
|
|
306
|
+
case kind
|
|
307
|
+
case hours
|
|
308
|
+
case days
|
|
309
|
+
case start
|
|
310
|
+
case end
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
public init(from decoder: any Decoder) throws {
|
|
314
|
+
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
315
|
+
let tag = try container.decode(String.self, forKey: .kind)
|
|
316
|
+
switch tag {
|
|
317
|
+
case "lastHours":
|
|
318
|
+
let hours = try container.decode(Int.self, forKey: .hours)
|
|
319
|
+
self = .lastHours(hours: hours)
|
|
320
|
+
case "lastDays":
|
|
321
|
+
let days = try container.decode(Int.self, forKey: .days)
|
|
322
|
+
self = .lastDays(days: days)
|
|
323
|
+
case "today":
|
|
324
|
+
self = .today
|
|
325
|
+
case "between":
|
|
326
|
+
let start = try container.decode(String.self, forKey: .start)
|
|
327
|
+
let end = try container.decode(String.self, forKey: .end)
|
|
328
|
+
self = .between(start: start, end: end)
|
|
329
|
+
default:
|
|
330
|
+
throw DecodingError.dataCorruptedError(forKey: .kind, in: container, debugDescription: "unknown TimeRange \(tag)")
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
public func encode(to encoder: any Encoder) throws {
|
|
335
|
+
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
336
|
+
switch self {
|
|
337
|
+
case .lastHours(let hours):
|
|
338
|
+
try container.encode("lastHours", forKey: .kind)
|
|
339
|
+
try container.encode(hours, forKey: .hours)
|
|
340
|
+
case .lastDays(let days):
|
|
341
|
+
try container.encode("lastDays", forKey: .kind)
|
|
342
|
+
try container.encode(days, forKey: .days)
|
|
343
|
+
case .today:
|
|
344
|
+
try container.encode("today", forKey: .kind)
|
|
345
|
+
case .between(let start, let end):
|
|
346
|
+
try container.encode("between", forKey: .kind)
|
|
347
|
+
try container.encode(start, forKey: .start)
|
|
348
|
+
try container.encode(end, forKey: .end)
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
public enum SleepStage: Codable, Equatable, Sendable {
|
|
354
|
+
case inBed
|
|
355
|
+
case awake
|
|
356
|
+
case asleep
|
|
357
|
+
case light
|
|
358
|
+
case deep
|
|
359
|
+
case rem
|
|
360
|
+
case unknown(raw: String)
|
|
361
|
+
|
|
362
|
+
private enum CodingKeys: String, CodingKey {
|
|
363
|
+
case kind
|
|
364
|
+
case raw
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
public init(from decoder: any Decoder) throws {
|
|
368
|
+
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
369
|
+
let tag = try container.decode(String.self, forKey: .kind)
|
|
370
|
+
switch tag {
|
|
371
|
+
case "inBed":
|
|
372
|
+
self = .inBed
|
|
373
|
+
case "awake":
|
|
374
|
+
self = .awake
|
|
375
|
+
case "asleep":
|
|
376
|
+
self = .asleep
|
|
377
|
+
case "light":
|
|
378
|
+
self = .light
|
|
379
|
+
case "deep":
|
|
380
|
+
self = .deep
|
|
381
|
+
case "rem":
|
|
382
|
+
self = .rem
|
|
383
|
+
case "unknown":
|
|
384
|
+
let raw = try container.decode(String.self, forKey: .raw)
|
|
385
|
+
self = .unknown(raw: raw)
|
|
386
|
+
default:
|
|
387
|
+
throw DecodingError.dataCorruptedError(forKey: .kind, in: container, debugDescription: "unknown SleepStage \(tag)")
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
public func encode(to encoder: any Encoder) throws {
|
|
392
|
+
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
393
|
+
switch self {
|
|
394
|
+
case .inBed:
|
|
395
|
+
try container.encode("inBed", forKey: .kind)
|
|
396
|
+
case .awake:
|
|
397
|
+
try container.encode("awake", forKey: .kind)
|
|
398
|
+
case .asleep:
|
|
399
|
+
try container.encode("asleep", forKey: .kind)
|
|
400
|
+
case .light:
|
|
401
|
+
try container.encode("light", forKey: .kind)
|
|
402
|
+
case .deep:
|
|
403
|
+
try container.encode("deep", forKey: .kind)
|
|
404
|
+
case .rem:
|
|
405
|
+
try container.encode("rem", forKey: .kind)
|
|
406
|
+
case .unknown(let raw):
|
|
407
|
+
try container.encode("unknown", forKey: .kind)
|
|
408
|
+
try container.encode(raw, forKey: .raw)
|
|
409
|
+
}
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
413
|
+
public enum WorkoutActivity: Codable, Equatable, Sendable {
|
|
414
|
+
case running
|
|
415
|
+
case walking
|
|
416
|
+
case cycling
|
|
417
|
+
case swimming
|
|
418
|
+
case strengthTraining
|
|
419
|
+
case other(label: String)
|
|
420
|
+
|
|
421
|
+
private enum CodingKeys: String, CodingKey {
|
|
422
|
+
case kind
|
|
423
|
+
case label
|
|
424
|
+
}
|
|
425
|
+
|
|
426
|
+
public init(from decoder: any Decoder) throws {
|
|
427
|
+
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
428
|
+
let tag = try container.decode(String.self, forKey: .kind)
|
|
429
|
+
switch tag {
|
|
430
|
+
case "running":
|
|
431
|
+
self = .running
|
|
432
|
+
case "walking":
|
|
433
|
+
self = .walking
|
|
434
|
+
case "cycling":
|
|
435
|
+
self = .cycling
|
|
436
|
+
case "swimming":
|
|
437
|
+
self = .swimming
|
|
438
|
+
case "strengthTraining":
|
|
439
|
+
self = .strengthTraining
|
|
440
|
+
case "other":
|
|
441
|
+
let label = try container.decode(String.self, forKey: .label)
|
|
442
|
+
self = .other(label: label)
|
|
443
|
+
default:
|
|
444
|
+
throw DecodingError.dataCorruptedError(forKey: .kind, in: container, debugDescription: "unknown WorkoutActivity \(tag)")
|
|
445
|
+
}
|
|
446
|
+
}
|
|
447
|
+
|
|
448
|
+
public func encode(to encoder: any Encoder) throws {
|
|
449
|
+
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
450
|
+
switch self {
|
|
451
|
+
case .running:
|
|
452
|
+
try container.encode("running", forKey: .kind)
|
|
453
|
+
case .walking:
|
|
454
|
+
try container.encode("walking", forKey: .kind)
|
|
455
|
+
case .cycling:
|
|
456
|
+
try container.encode("cycling", forKey: .kind)
|
|
457
|
+
case .swimming:
|
|
458
|
+
try container.encode("swimming", forKey: .kind)
|
|
459
|
+
case .strengthTraining:
|
|
460
|
+
try container.encode("strengthTraining", forKey: .kind)
|
|
461
|
+
case .other(let label):
|
|
462
|
+
try container.encode("other", forKey: .kind)
|
|
463
|
+
try container.encode(label, forKey: .label)
|
|
464
|
+
}
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
/// What the SDK believes about delivery right now. Wire spelling matches DiagnosticsWire.state
|
|
469
|
+
/// and Apple's DiagnosticsState Encodable.
|
|
470
|
+
public enum DiagnosticsState: Codable, Equatable, Sendable {
|
|
471
|
+
case healthy
|
|
472
|
+
case quiet(since: String)
|
|
473
|
+
case backgroundRestricted(reason: BackgroundRestrictionReason?)
|
|
474
|
+
case backgroundRefreshUnscheduled
|
|
475
|
+
case pendingRetry
|
|
476
|
+
case linkRevoked
|
|
477
|
+
case devIDMismatch
|
|
478
|
+
|
|
479
|
+
private enum CodingKeys: String, CodingKey {
|
|
480
|
+
case state
|
|
481
|
+
case since
|
|
482
|
+
case reason
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
public init(from decoder: any Decoder) throws {
|
|
486
|
+
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
487
|
+
let tag = try container.decode(String.self, forKey: .state)
|
|
488
|
+
switch tag {
|
|
489
|
+
case "healthy":
|
|
490
|
+
self = .healthy
|
|
491
|
+
case "quiet":
|
|
492
|
+
let since = try container.decode(String.self, forKey: .since)
|
|
493
|
+
self = .quiet(since: since)
|
|
494
|
+
case "backgroundRestricted":
|
|
495
|
+
let reason = try container.decodeIfPresent(BackgroundRestrictionReason.self, forKey: .reason)
|
|
496
|
+
self = .backgroundRestricted(reason: reason)
|
|
497
|
+
case "backgroundRefreshUnscheduled":
|
|
498
|
+
self = .backgroundRefreshUnscheduled
|
|
499
|
+
case "pendingRetry":
|
|
500
|
+
self = .pendingRetry
|
|
501
|
+
case "linkRevoked":
|
|
502
|
+
self = .linkRevoked
|
|
503
|
+
case "devIDMismatch":
|
|
504
|
+
self = .devIDMismatch
|
|
505
|
+
default:
|
|
506
|
+
throw DecodingError.dataCorruptedError(forKey: .state, in: container, debugDescription: "unknown DiagnosticsState \(tag)")
|
|
507
|
+
}
|
|
508
|
+
}
|
|
509
|
+
|
|
510
|
+
public func encode(to encoder: any Encoder) throws {
|
|
511
|
+
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
512
|
+
switch self {
|
|
513
|
+
case .healthy:
|
|
514
|
+
try container.encode("healthy", forKey: .state)
|
|
515
|
+
case .quiet(let since):
|
|
516
|
+
try container.encode("quiet", forKey: .state)
|
|
517
|
+
try container.encode(since, forKey: .since)
|
|
518
|
+
case .backgroundRestricted(let reason):
|
|
519
|
+
try container.encode("backgroundRestricted", forKey: .state)
|
|
520
|
+
try container.encodeIfPresent(reason, forKey: .reason)
|
|
521
|
+
case .backgroundRefreshUnscheduled:
|
|
522
|
+
try container.encode("backgroundRefreshUnscheduled", forKey: .state)
|
|
523
|
+
case .pendingRetry:
|
|
524
|
+
try container.encode("pendingRetry", forKey: .state)
|
|
525
|
+
case .linkRevoked:
|
|
526
|
+
try container.encode("linkRevoked", forKey: .state)
|
|
527
|
+
case .devIDMismatch:
|
|
528
|
+
try container.encode("devIDMismatch", forKey: .state)
|
|
529
|
+
}
|
|
530
|
+
}
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
/// What a subscription delivers. A stream can fail or finish, and without saying so the
|
|
534
|
+
/// framework layer has to invent a convention for both - two of those, one per wrapper, is a
|
|
535
|
+
/// contract nobody wrote down.
|
|
536
|
+
public enum StreamMessage: Codable, Equatable, Sendable {
|
|
537
|
+
case data(element: BridgeJSON)
|
|
538
|
+
case error(error: TerraErrorPayload)
|
|
539
|
+
case complete
|
|
540
|
+
|
|
541
|
+
private enum CodingKeys: String, CodingKey {
|
|
542
|
+
case kind
|
|
543
|
+
case element
|
|
544
|
+
case error
|
|
545
|
+
}
|
|
546
|
+
|
|
547
|
+
public init(from decoder: any Decoder) throws {
|
|
548
|
+
let container = try decoder.container(keyedBy: CodingKeys.self)
|
|
549
|
+
let tag = try container.decode(String.self, forKey: .kind)
|
|
550
|
+
switch tag {
|
|
551
|
+
case "data":
|
|
552
|
+
let element = try container.decode(BridgeJSON.self, forKey: .element)
|
|
553
|
+
self = .data(element: element)
|
|
554
|
+
case "error":
|
|
555
|
+
let error = try container.decode(TerraErrorPayload.self, forKey: .error)
|
|
556
|
+
self = .error(error: error)
|
|
557
|
+
case "complete":
|
|
558
|
+
self = .complete
|
|
559
|
+
default:
|
|
560
|
+
throw DecodingError.dataCorruptedError(forKey: .kind, in: container, debugDescription: "unknown StreamMessage \(tag)")
|
|
561
|
+
}
|
|
562
|
+
}
|
|
563
|
+
|
|
564
|
+
public func encode(to encoder: any Encoder) throws {
|
|
565
|
+
var container = encoder.container(keyedBy: CodingKeys.self)
|
|
566
|
+
switch self {
|
|
567
|
+
case .data(let element):
|
|
568
|
+
try container.encode("data", forKey: .kind)
|
|
569
|
+
try container.encode(element, forKey: .element)
|
|
570
|
+
case .error(let error):
|
|
571
|
+
try container.encode("error", forKey: .kind)
|
|
572
|
+
try container.encode(error, forKey: .error)
|
|
573
|
+
case .complete:
|
|
574
|
+
try container.encode("complete", forKey: .kind)
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
/// Who recorded a sample. The only stable handle an app has for filtering by app or device.
|
|
580
|
+
public struct SampleSource: Codable, Equatable, Sendable {
|
|
581
|
+
public var name: String
|
|
582
|
+
public var bundleId: String
|
|
583
|
+
public var productType: String?
|
|
584
|
+
public var deviceType: String?
|
|
585
|
+
|
|
586
|
+
public init(name: String, bundleId: String, productType: String? = nil, deviceType: String? = nil) {
|
|
587
|
+
self.name = name
|
|
588
|
+
self.bundleId = bundleId
|
|
589
|
+
self.productType = productType
|
|
590
|
+
self.deviceType = deviceType
|
|
591
|
+
}
|
|
592
|
+
}
|
|
593
|
+
|
|
594
|
+
/// A link record. A value, not a handle: Apple's Connection carries sync and disconnect
|
|
595
|
+
/// methods, and an object with behaviour cannot cross the bridge, so those are ops on the
|
|
596
|
+
/// client.
|
|
597
|
+
public struct Connection: Codable, Equatable, Sendable {
|
|
598
|
+
public var source: Source
|
|
599
|
+
public var userId: String
|
|
600
|
+
/// Android's StoredConnection carries the store-side id. Apple's Connection does not.
|
|
601
|
+
///
|
|
602
|
+
/// Available on android only.
|
|
603
|
+
public var providerUserId: String?
|
|
604
|
+
|
|
605
|
+
public init(source: Source, userId: String, providerUserId: String? = nil) {
|
|
606
|
+
self.source = source
|
|
607
|
+
self.userId = userId
|
|
608
|
+
self.providerUserId = providerUserId
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
|
|
612
|
+
public struct HeartRateSample: Codable, Equatable, Sendable {
|
|
613
|
+
public var id: String
|
|
614
|
+
public var time: String
|
|
615
|
+
public var beatsPerMinute: Double
|
|
616
|
+
public var source: SampleSource
|
|
617
|
+
public var motionContext: MotionContext?
|
|
618
|
+
public var userEntered: Bool
|
|
619
|
+
public var timeZone: String?
|
|
620
|
+
|
|
621
|
+
public init(id: String, time: String, beatsPerMinute: Double, source: SampleSource, motionContext: MotionContext? = nil, userEntered: Bool, timeZone: String? = nil) {
|
|
622
|
+
self.id = id
|
|
623
|
+
self.time = time
|
|
624
|
+
self.beatsPerMinute = beatsPerMinute
|
|
625
|
+
self.source = source
|
|
626
|
+
self.motionContext = motionContext
|
|
627
|
+
self.userEntered = userEntered
|
|
628
|
+
self.timeZone = timeZone
|
|
629
|
+
}
|
|
630
|
+
}
|
|
631
|
+
|
|
632
|
+
/// A step total over an interval. Apple derives the id from the source and start; Android
|
|
633
|
+
/// carries a RecordId when it has one, so the id is optional on the wire.
|
|
634
|
+
public struct StepCount: Codable, Equatable, Sendable {
|
|
635
|
+
public var id: String?
|
|
636
|
+
public var start: String
|
|
637
|
+
public var end: String
|
|
638
|
+
public var steps: Int
|
|
639
|
+
public var source: SampleSource
|
|
640
|
+
public var userEntered: Bool
|
|
641
|
+
public var timeZone: String?
|
|
642
|
+
|
|
643
|
+
public init(id: String? = nil, start: String, end: String, steps: Int, source: SampleSource, userEntered: Bool, timeZone: String? = nil) {
|
|
644
|
+
self.id = id
|
|
645
|
+
self.start = start
|
|
646
|
+
self.end = end
|
|
647
|
+
self.steps = steps
|
|
648
|
+
self.source = source
|
|
649
|
+
self.userEntered = userEntered
|
|
650
|
+
self.timeZone = timeZone
|
|
651
|
+
}
|
|
652
|
+
}
|
|
653
|
+
|
|
654
|
+
public struct SleepSegment: Codable, Equatable, Sendable {
|
|
655
|
+
public var id: String
|
|
656
|
+
public var start: String
|
|
657
|
+
public var end: String
|
|
658
|
+
public var stage: SleepStage
|
|
659
|
+
public var source: SampleSource
|
|
660
|
+
public var userEntered: Bool
|
|
661
|
+
public var timeZone: String?
|
|
662
|
+
|
|
663
|
+
public init(id: String, start: String, end: String, stage: SleepStage, source: SampleSource, userEntered: Bool, timeZone: String? = nil) {
|
|
664
|
+
self.id = id
|
|
665
|
+
self.start = start
|
|
666
|
+
self.end = end
|
|
667
|
+
self.stage = stage
|
|
668
|
+
self.source = source
|
|
669
|
+
self.userEntered = userEntered
|
|
670
|
+
self.timeZone = timeZone
|
|
671
|
+
}
|
|
672
|
+
}
|
|
673
|
+
|
|
674
|
+
/// indoor is optional because Health Connect does not always record it; Apple always has an
|
|
675
|
+
/// answer.
|
|
676
|
+
public struct Workout: Codable, Equatable, Sendable {
|
|
677
|
+
public var id: String
|
|
678
|
+
public var start: String
|
|
679
|
+
public var end: String
|
|
680
|
+
public var activity: WorkoutActivity
|
|
681
|
+
public var activityTypeCode: Int
|
|
682
|
+
public var indoor: Bool?
|
|
683
|
+
public var activeEnergyKilocalories: Double?
|
|
684
|
+
public var distanceMeters: Double?
|
|
685
|
+
public var source: SampleSource
|
|
686
|
+
public var userEntered: Bool
|
|
687
|
+
public var timeZone: String?
|
|
688
|
+
|
|
689
|
+
public init(id: String, start: String, end: String, activity: WorkoutActivity, activityTypeCode: Int, indoor: Bool? = nil, activeEnergyKilocalories: Double? = nil, distanceMeters: Double? = nil, source: SampleSource, userEntered: Bool, timeZone: String? = nil) {
|
|
690
|
+
self.id = id
|
|
691
|
+
self.start = start
|
|
692
|
+
self.end = end
|
|
693
|
+
self.activity = activity
|
|
694
|
+
self.activityTypeCode = activityTypeCode
|
|
695
|
+
self.indoor = indoor
|
|
696
|
+
self.activeEnergyKilocalories = activeEnergyKilocalories
|
|
697
|
+
self.distanceMeters = distanceMeters
|
|
698
|
+
self.source = source
|
|
699
|
+
self.userEntered = userEntered
|
|
700
|
+
self.timeZone = timeZone
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
|
|
704
|
+
/// A day whose data changed. Carries no health value by construction.
|
|
705
|
+
public struct HealthChange: Codable, Equatable, Sendable {
|
|
706
|
+
public var category: DataCategory
|
|
707
|
+
public var day: String
|
|
708
|
+
|
|
709
|
+
public init(category: DataCategory, day: String) {
|
|
710
|
+
self.category = category
|
|
711
|
+
self.day = day
|
|
712
|
+
}
|
|
713
|
+
}
|
|
714
|
+
|
|
715
|
+
public struct WorkoutScope: Codable, Equatable, Sendable {
|
|
716
|
+
public var activity: WorkoutActivity
|
|
717
|
+
public var energy: Bool
|
|
718
|
+
public var distance: Bool
|
|
719
|
+
|
|
720
|
+
public init(activity: WorkoutActivity, energy: Bool, distance: Bool) {
|
|
721
|
+
self.activity = activity
|
|
722
|
+
self.energy = energy
|
|
723
|
+
self.distance = distance
|
|
724
|
+
}
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
/// Lists rather than sets: JSON has no set, so the category lists are marked `set` and every
|
|
728
|
+
/// generated codec de-duplicates and sorts them, so two orderings compare equal.
|
|
729
|
+
public struct HealthAccess: Codable, Equatable, Sendable {
|
|
730
|
+
@CaseSet public var read: [DataCategory]
|
|
731
|
+
@CaseSet public var write: [DataCategory]
|
|
732
|
+
public var workouts: [WorkoutScope]
|
|
733
|
+
|
|
734
|
+
public init(read: [DataCategory], write: [DataCategory], workouts: [WorkoutScope]) {
|
|
735
|
+
self.read = read
|
|
736
|
+
self.write = write
|
|
737
|
+
self.workouts = workouts
|
|
738
|
+
}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
public struct HeartRateEntry: Codable, Equatable, Sendable {
|
|
742
|
+
public var time: String
|
|
743
|
+
public var beatsPerMinute: Double
|
|
744
|
+
public var recordId: String?
|
|
745
|
+
|
|
746
|
+
public init(time: String, beatsPerMinute: Double, recordId: String? = nil) {
|
|
747
|
+
self.time = time
|
|
748
|
+
self.beatsPerMinute = beatsPerMinute
|
|
749
|
+
self.recordId = recordId
|
|
750
|
+
}
|
|
751
|
+
}
|
|
752
|
+
|
|
753
|
+
public struct StepEntry: Codable, Equatable, Sendable {
|
|
754
|
+
public var start: String
|
|
755
|
+
public var end: String
|
|
756
|
+
public var steps: Int
|
|
757
|
+
public var recordId: String?
|
|
758
|
+
|
|
759
|
+
public init(start: String, end: String, steps: Int, recordId: String? = nil) {
|
|
760
|
+
self.start = start
|
|
761
|
+
self.end = end
|
|
762
|
+
self.steps = steps
|
|
763
|
+
self.recordId = recordId
|
|
764
|
+
}
|
|
765
|
+
}
|
|
766
|
+
|
|
767
|
+
public struct SleepEntry: Codable, Equatable, Sendable {
|
|
768
|
+
public var start: String
|
|
769
|
+
public var end: String
|
|
770
|
+
public var stage: SleepStage
|
|
771
|
+
public var recordId: String?
|
|
772
|
+
|
|
773
|
+
public init(start: String, end: String, stage: SleepStage, recordId: String? = nil) {
|
|
774
|
+
self.start = start
|
|
775
|
+
self.end = end
|
|
776
|
+
self.stage = stage
|
|
777
|
+
self.recordId = recordId
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
|
|
781
|
+
public struct WorkoutEntry: Codable, Equatable, Sendable {
|
|
782
|
+
public var start: String
|
|
783
|
+
public var end: String
|
|
784
|
+
public var activity: WorkoutActivity
|
|
785
|
+
public var totalEnergyKilocalories: Double?
|
|
786
|
+
public var totalDistanceMeters: Double?
|
|
787
|
+
public var recordId: String?
|
|
788
|
+
|
|
789
|
+
public init(start: String, end: String, activity: WorkoutActivity, totalEnergyKilocalories: Double? = nil, totalDistanceMeters: Double? = nil, recordId: String? = nil) {
|
|
790
|
+
self.start = start
|
|
791
|
+
self.end = end
|
|
792
|
+
self.activity = activity
|
|
793
|
+
self.totalEnergyKilocalories = totalEnergyKilocalories
|
|
794
|
+
self.totalDistanceMeters = totalDistanceMeters
|
|
795
|
+
self.recordId = recordId
|
|
796
|
+
}
|
|
797
|
+
}
|
|
798
|
+
|
|
799
|
+
public struct BodyEntry: Codable, Equatable, Sendable {
|
|
800
|
+
public var time: String
|
|
801
|
+
public var bodyMassKilograms: Double?
|
|
802
|
+
public var bodyFatPercent: Double?
|
|
803
|
+
public var bodyMassIndex: Double?
|
|
804
|
+
public var heightMeters: Double?
|
|
805
|
+
public var leanBodyMassKilograms: Double?
|
|
806
|
+
public var bodyTemperatureCelsius: Double?
|
|
807
|
+
public var oxygenSaturationPercent: Double?
|
|
808
|
+
public var bloodGlucoseMilligramsPerDeciliter: Double?
|
|
809
|
+
public var bloodPressureSystolicMillimetersOfMercury: Double?
|
|
810
|
+
public var bloodPressureDiastolicMillimetersOfMercury: Double?
|
|
811
|
+
public var recordId: String?
|
|
812
|
+
|
|
813
|
+
public init(time: String, bodyMassKilograms: Double? = nil, bodyFatPercent: Double? = nil, bodyMassIndex: Double? = nil, heightMeters: Double? = nil, leanBodyMassKilograms: Double? = nil, bodyTemperatureCelsius: Double? = nil, oxygenSaturationPercent: Double? = nil, bloodGlucoseMilligramsPerDeciliter: Double? = nil, bloodPressureSystolicMillimetersOfMercury: Double? = nil, bloodPressureDiastolicMillimetersOfMercury: Double? = nil, recordId: String? = nil) {
|
|
814
|
+
self.time = time
|
|
815
|
+
self.bodyMassKilograms = bodyMassKilograms
|
|
816
|
+
self.bodyFatPercent = bodyFatPercent
|
|
817
|
+
self.bodyMassIndex = bodyMassIndex
|
|
818
|
+
self.heightMeters = heightMeters
|
|
819
|
+
self.leanBodyMassKilograms = leanBodyMassKilograms
|
|
820
|
+
self.bodyTemperatureCelsius = bodyTemperatureCelsius
|
|
821
|
+
self.oxygenSaturationPercent = oxygenSaturationPercent
|
|
822
|
+
self.bloodGlucoseMilligramsPerDeciliter = bloodGlucoseMilligramsPerDeciliter
|
|
823
|
+
self.bloodPressureSystolicMillimetersOfMercury = bloodPressureSystolicMillimetersOfMercury
|
|
824
|
+
self.bloodPressureDiastolicMillimetersOfMercury = bloodPressureDiastolicMillimetersOfMercury
|
|
825
|
+
self.recordId = recordId
|
|
826
|
+
}
|
|
827
|
+
}
|
|
828
|
+
|
|
829
|
+
/// Every field optional and every unit in the name, matching NutritionEntry.Nutrients on both
|
|
830
|
+
/// platforms field for field.
|
|
831
|
+
public struct Nutrients: Codable, Equatable, Sendable {
|
|
832
|
+
public var energyKilocalories: Double?
|
|
833
|
+
public var proteinGrams: Double?
|
|
834
|
+
public var carbohydratesGrams: Double?
|
|
835
|
+
public var fiberGrams: Double?
|
|
836
|
+
public var sugarGrams: Double?
|
|
837
|
+
public var fatTotalGrams: Double?
|
|
838
|
+
public var fatSaturatedGrams: Double?
|
|
839
|
+
public var fatMonounsaturatedGrams: Double?
|
|
840
|
+
public var fatPolyunsaturatedGrams: Double?
|
|
841
|
+
public var cholesterolMilligrams: Double?
|
|
842
|
+
public var sodiumMilligrams: Double?
|
|
843
|
+
public var potassiumMilligrams: Double?
|
|
844
|
+
public var calciumMilligrams: Double?
|
|
845
|
+
public var ironMilligrams: Double?
|
|
846
|
+
public var magnesiumMilligrams: Double?
|
|
847
|
+
public var zincMilligrams: Double?
|
|
848
|
+
public var waterLiters: Double?
|
|
849
|
+
public var caffeineMilligrams: Double?
|
|
850
|
+
public var vitaminAMicrograms: Double?
|
|
851
|
+
public var vitaminCMilligrams: Double?
|
|
852
|
+
public var vitaminDMicrograms: Double?
|
|
853
|
+
public var vitaminEMilligrams: Double?
|
|
854
|
+
public var vitaminKMicrograms: Double?
|
|
855
|
+
public var vitaminB6Milligrams: Double?
|
|
856
|
+
public var vitaminB12Micrograms: Double?
|
|
857
|
+
public var folateMicrograms: Double?
|
|
858
|
+
public var thiaminMilligrams: Double?
|
|
859
|
+
public var riboflavinMilligrams: Double?
|
|
860
|
+
public var niacinMilligrams: Double?
|
|
861
|
+
public var biotinMicrograms: Double?
|
|
862
|
+
public var pantothenicAcidMilligrams: Double?
|
|
863
|
+
public var phosphorusMilligrams: Double?
|
|
864
|
+
public var iodineMicrograms: Double?
|
|
865
|
+
public var chromiumMicrograms: Double?
|
|
866
|
+
public var copperMilligrams: Double?
|
|
867
|
+
public var manganeseMilligrams: Double?
|
|
868
|
+
public var molybdenumMicrograms: Double?
|
|
869
|
+
public var seleniumMicrograms: Double?
|
|
870
|
+
public var chlorideMilligrams: Double?
|
|
871
|
+
|
|
872
|
+
public init(energyKilocalories: Double? = nil, proteinGrams: Double? = nil, carbohydratesGrams: Double? = nil, fiberGrams: Double? = nil, sugarGrams: Double? = nil, fatTotalGrams: Double? = nil, fatSaturatedGrams: Double? = nil, fatMonounsaturatedGrams: Double? = nil, fatPolyunsaturatedGrams: Double? = nil, cholesterolMilligrams: Double? = nil, sodiumMilligrams: Double? = nil, potassiumMilligrams: Double? = nil, calciumMilligrams: Double? = nil, ironMilligrams: Double? = nil, magnesiumMilligrams: Double? = nil, zincMilligrams: Double? = nil, waterLiters: Double? = nil, caffeineMilligrams: Double? = nil, vitaminAMicrograms: Double? = nil, vitaminCMilligrams: Double? = nil, vitaminDMicrograms: Double? = nil, vitaminEMilligrams: Double? = nil, vitaminKMicrograms: Double? = nil, vitaminB6Milligrams: Double? = nil, vitaminB12Micrograms: Double? = nil, folateMicrograms: Double? = nil, thiaminMilligrams: Double? = nil, riboflavinMilligrams: Double? = nil, niacinMilligrams: Double? = nil, biotinMicrograms: Double? = nil, pantothenicAcidMilligrams: Double? = nil, phosphorusMilligrams: Double? = nil, iodineMicrograms: Double? = nil, chromiumMicrograms: Double? = nil, copperMilligrams: Double? = nil, manganeseMilligrams: Double? = nil, molybdenumMicrograms: Double? = nil, seleniumMicrograms: Double? = nil, chlorideMilligrams: Double? = nil) {
|
|
873
|
+
self.energyKilocalories = energyKilocalories
|
|
874
|
+
self.proteinGrams = proteinGrams
|
|
875
|
+
self.carbohydratesGrams = carbohydratesGrams
|
|
876
|
+
self.fiberGrams = fiberGrams
|
|
877
|
+
self.sugarGrams = sugarGrams
|
|
878
|
+
self.fatTotalGrams = fatTotalGrams
|
|
879
|
+
self.fatSaturatedGrams = fatSaturatedGrams
|
|
880
|
+
self.fatMonounsaturatedGrams = fatMonounsaturatedGrams
|
|
881
|
+
self.fatPolyunsaturatedGrams = fatPolyunsaturatedGrams
|
|
882
|
+
self.cholesterolMilligrams = cholesterolMilligrams
|
|
883
|
+
self.sodiumMilligrams = sodiumMilligrams
|
|
884
|
+
self.potassiumMilligrams = potassiumMilligrams
|
|
885
|
+
self.calciumMilligrams = calciumMilligrams
|
|
886
|
+
self.ironMilligrams = ironMilligrams
|
|
887
|
+
self.magnesiumMilligrams = magnesiumMilligrams
|
|
888
|
+
self.zincMilligrams = zincMilligrams
|
|
889
|
+
self.waterLiters = waterLiters
|
|
890
|
+
self.caffeineMilligrams = caffeineMilligrams
|
|
891
|
+
self.vitaminAMicrograms = vitaminAMicrograms
|
|
892
|
+
self.vitaminCMilligrams = vitaminCMilligrams
|
|
893
|
+
self.vitaminDMicrograms = vitaminDMicrograms
|
|
894
|
+
self.vitaminEMilligrams = vitaminEMilligrams
|
|
895
|
+
self.vitaminKMicrograms = vitaminKMicrograms
|
|
896
|
+
self.vitaminB6Milligrams = vitaminB6Milligrams
|
|
897
|
+
self.vitaminB12Micrograms = vitaminB12Micrograms
|
|
898
|
+
self.folateMicrograms = folateMicrograms
|
|
899
|
+
self.thiaminMilligrams = thiaminMilligrams
|
|
900
|
+
self.riboflavinMilligrams = riboflavinMilligrams
|
|
901
|
+
self.niacinMilligrams = niacinMilligrams
|
|
902
|
+
self.biotinMicrograms = biotinMicrograms
|
|
903
|
+
self.pantothenicAcidMilligrams = pantothenicAcidMilligrams
|
|
904
|
+
self.phosphorusMilligrams = phosphorusMilligrams
|
|
905
|
+
self.iodineMicrograms = iodineMicrograms
|
|
906
|
+
self.chromiumMicrograms = chromiumMicrograms
|
|
907
|
+
self.copperMilligrams = copperMilligrams
|
|
908
|
+
self.manganeseMilligrams = manganeseMilligrams
|
|
909
|
+
self.molybdenumMicrograms = molybdenumMicrograms
|
|
910
|
+
self.seleniumMicrograms = seleniumMicrograms
|
|
911
|
+
self.chlorideMilligrams = chlorideMilligrams
|
|
912
|
+
}
|
|
913
|
+
}
|
|
914
|
+
|
|
915
|
+
public struct NutritionEntry: Codable, Equatable, Sendable {
|
|
916
|
+
public var start: String
|
|
917
|
+
public var end: String
|
|
918
|
+
public var name: String?
|
|
919
|
+
public var nutrients: Nutrients
|
|
920
|
+
public var recordId: String?
|
|
921
|
+
|
|
922
|
+
public init(start: String, end: String, name: String? = nil, nutrients: Nutrients, recordId: String? = nil) {
|
|
923
|
+
self.start = start
|
|
924
|
+
self.end = end
|
|
925
|
+
self.name = name
|
|
926
|
+
self.nutrients = nutrients
|
|
927
|
+
self.recordId = recordId
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
|
|
931
|
+
/// An error carried as a value rather than thrown, inside a sync result. The same shape the
|
|
932
|
+
/// bridge rejects a promise with.
|
|
933
|
+
public struct TerraErrorPayload: Codable, Equatable, Sendable {
|
|
934
|
+
public var code: String
|
|
935
|
+
public var retryable: Bool
|
|
936
|
+
public var message: String
|
|
937
|
+
public var source: Source?
|
|
938
|
+
public var details: BridgeJSON?
|
|
939
|
+
|
|
940
|
+
public init(code: String, retryable: Bool, message: String, source: Source? = nil, details: BridgeJSON? = nil) {
|
|
941
|
+
self.code = code
|
|
942
|
+
self.retryable = retryable
|
|
943
|
+
self.message = message
|
|
944
|
+
self.source = source
|
|
945
|
+
self.details = details
|
|
946
|
+
}
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
/// Available on ios only.
|
|
950
|
+
public struct PlannedWorkout: Codable, Equatable, Sendable {
|
|
951
|
+
public var id: String
|
|
952
|
+
public var plannedOn: String
|
|
953
|
+
public var activity: WorkoutActivity
|
|
954
|
+
public var title: String?
|
|
955
|
+
public var completedAt: String?
|
|
956
|
+
|
|
957
|
+
public init(id: String, plannedOn: String, activity: WorkoutActivity, title: String? = nil, completedAt: String? = nil) {
|
|
958
|
+
self.id = id
|
|
959
|
+
self.plannedOn = plannedOn
|
|
960
|
+
self.activity = activity
|
|
961
|
+
self.title = title
|
|
962
|
+
self.completedAt = completedAt
|
|
963
|
+
}
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
/// The flat object both SDKs already emit: `at`, `event`, and whatever keys that kind carries.
|
|
967
|
+
/// Carried through unchanged rather than reshaped, because reshaping it would be a hand-written
|
|
968
|
+
/// second contract on each platform that no vector could pin - and the encoding it would be
|
|
969
|
+
/// translating is one DiagnosticsWire and Apple's Encodable already agree on, and that
|
|
970
|
+
/// EventPrivacyTest already guards against carrying a health value.
|
|
971
|
+
public typealias TerraEvent = BridgeJSON
|
|
972
|
+
|
|
973
|
+
/// The redacted report, carried as the wire object DiagnosticsWire.report and Apple's
|
|
974
|
+
/// SupportReport.json already produce.
|
|
975
|
+
public struct SupportReport: Codable, Equatable, Sendable {
|
|
976
|
+
public var sdkVersion: String
|
|
977
|
+
public var generatedAt: String
|
|
978
|
+
public var state: DiagnosticsState
|
|
979
|
+
public var lastDelivery: String?
|
|
980
|
+
public var isConnected: Bool
|
|
981
|
+
public var requestedCategories: [String]
|
|
982
|
+
public var requestedWrites: [String]
|
|
983
|
+
public var requestedWorkouts: [String]
|
|
984
|
+
public var recentEvents: [TerraEvent]
|
|
985
|
+
|
|
986
|
+
public init(sdkVersion: String, generatedAt: String, state: DiagnosticsState, lastDelivery: String? = nil, isConnected: Bool, requestedCategories: [String], requestedWrites: [String], requestedWorkouts: [String], recentEvents: [TerraEvent]) {
|
|
987
|
+
self.sdkVersion = sdkVersion
|
|
988
|
+
self.generatedAt = generatedAt
|
|
989
|
+
self.state = state
|
|
990
|
+
self.lastDelivery = lastDelivery
|
|
991
|
+
self.isConnected = isConnected
|
|
992
|
+
self.requestedCategories = requestedCategories
|
|
993
|
+
self.requestedWrites = requestedWrites
|
|
994
|
+
self.requestedWorkouts = requestedWorkouts
|
|
995
|
+
self.recentEvents = recentEvents
|
|
996
|
+
}
|
|
997
|
+
}
|
|
998
|
+
|
|
999
|
+
/// What the JS side needs to know about the native client it is attaching to. bootstrapped
|
|
1000
|
+
/// false is a host setup bug, and the wrapper says so with the exact line to add.
|
|
1001
|
+
public struct BootstrapState: Codable, Equatable, Sendable {
|
|
1002
|
+
public var bootstrapped: Bool
|
|
1003
|
+
public var devId: String?
|
|
1004
|
+
public var platform: String
|
|
1005
|
+
public var sdkVersion: String
|
|
1006
|
+
public var backgroundRegistered: Bool
|
|
1007
|
+
|
|
1008
|
+
public init(bootstrapped: Bool, devId: String? = nil, platform: String, sdkVersion: String, backgroundRegistered: Bool) {
|
|
1009
|
+
self.bootstrapped = bootstrapped
|
|
1010
|
+
self.devId = devId
|
|
1011
|
+
self.platform = platform
|
|
1012
|
+
self.sdkVersion = sdkVersion
|
|
1013
|
+
self.backgroundRegistered = backgroundRegistered
|
|
1014
|
+
}
|
|
1015
|
+
}
|
|
1016
|
+
|
|
1017
|
+
/// The broker asking JS for a link token. Answered by token.resolve or token.reject with the
|
|
1018
|
+
/// same requestId.
|
|
1019
|
+
public struct TokenRequest: Codable, Equatable, Sendable {
|
|
1020
|
+
public var requestId: String
|
|
1021
|
+
|
|
1022
|
+
public init(requestId: String) {
|
|
1023
|
+
self.requestId = requestId
|
|
1024
|
+
}
|
|
1025
|
+
}
|
|
1026
|
+
|
|
1027
|
+
/// No request fields, or no response value.
|
|
1028
|
+
public struct Empty: Codable, Equatable, Sendable {
|
|
1029
|
+
public init() {}
|
|
1030
|
+
}
|
|
1031
|
+
|
|
1032
|
+
public struct SourceRequest: Codable, Equatable, Sendable {
|
|
1033
|
+
public var source: Source?
|
|
1034
|
+
|
|
1035
|
+
public init(source: Source? = nil) {
|
|
1036
|
+
self.source = source
|
|
1037
|
+
}
|
|
1038
|
+
}
|
|
1039
|
+
|
|
1040
|
+
public struct RangeRequest: Codable, Equatable, Sendable {
|
|
1041
|
+
public var range: TimeRange
|
|
1042
|
+
|
|
1043
|
+
public init(range: TimeRange) {
|
|
1044
|
+
self.range = range
|
|
1045
|
+
}
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
public struct CategoryRequest: Codable, Equatable, Sendable {
|
|
1049
|
+
public var category: DataCategory
|
|
1050
|
+
public var source: Source?
|
|
1051
|
+
|
|
1052
|
+
public init(category: DataCategory, source: Source? = nil) {
|
|
1053
|
+
self.category = category
|
|
1054
|
+
self.source = source
|
|
1055
|
+
}
|
|
1056
|
+
}
|
|
1057
|
+
|
|
1058
|
+
public struct RecordIdRequest: Codable, Equatable, Sendable {
|
|
1059
|
+
public var id: String
|
|
1060
|
+
|
|
1061
|
+
public init(id: String) {
|
|
1062
|
+
self.id = id
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
|
|
1066
|
+
public struct ConnectRequest: Codable, Equatable, Sendable {
|
|
1067
|
+
public var source: Source?
|
|
1068
|
+
public var endUser: EndUser
|
|
1069
|
+
/// A grant already in hand, from a QR code or a deep link. Absent means the token provider is
|
|
1070
|
+
/// asked.
|
|
1071
|
+
public var token: String?
|
|
1072
|
+
|
|
1073
|
+
public init(source: Source? = nil, endUser: EndUser, token: String? = nil) {
|
|
1074
|
+
self.source = source
|
|
1075
|
+
self.endUser = endUser
|
|
1076
|
+
self.token = token
|
|
1077
|
+
}
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
public struct PermissionRequest: Codable, Equatable, Sendable {
|
|
1081
|
+
@CaseSet public var read: [DataCategory]
|
|
1082
|
+
@CaseSet public var write: [DataCategory]
|
|
1083
|
+
public var workouts: [WorkoutScope]
|
|
1084
|
+
public var source: Source?
|
|
1085
|
+
|
|
1086
|
+
public init(read: [DataCategory], write: [DataCategory], workouts: [WorkoutScope], source: Source? = nil) {
|
|
1087
|
+
self.read = read
|
|
1088
|
+
self.write = write
|
|
1089
|
+
self.workouts = workouts
|
|
1090
|
+
self.source = source
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
/// What the sheet granted. Android answers with the access this call obtained; HealthKit will
|
|
1095
|
+
/// not report read grants, so Apple answers nothing at all.
|
|
1096
|
+
public struct PermissionGrant: Codable, Equatable, Sendable {
|
|
1097
|
+
/// Available on android only.
|
|
1098
|
+
public var granted: HealthAccess?
|
|
1099
|
+
|
|
1100
|
+
public init(granted: HealthAccess? = nil) {
|
|
1101
|
+
self.granted = granted
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
public struct TokenResolveRequest: Codable, Equatable, Sendable {
|
|
1106
|
+
public var requestId: String
|
|
1107
|
+
public var token: String
|
|
1108
|
+
|
|
1109
|
+
public init(requestId: String, token: String) {
|
|
1110
|
+
self.requestId = requestId
|
|
1111
|
+
self.token = token
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
public struct TokenRejectRequest: Codable, Equatable, Sendable {
|
|
1116
|
+
public var requestId: String
|
|
1117
|
+
public var message: String
|
|
1118
|
+
|
|
1119
|
+
public init(requestId: String, message: String) {
|
|
1120
|
+
self.requestId = requestId
|
|
1121
|
+
self.message = message
|
|
1122
|
+
}
|
|
1123
|
+
}
|
|
1124
|
+
|
|
1125
|
+
public struct TokenProviderRequest: Codable, Equatable, Sendable {
|
|
1126
|
+
public var present: Bool
|
|
1127
|
+
public var timeoutMs: Int
|
|
1128
|
+
|
|
1129
|
+
public init(present: Bool, timeoutMs: Int) {
|
|
1130
|
+
self.present = present
|
|
1131
|
+
self.timeoutMs = timeoutMs
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
|
|
1135
|
+
/// Available on ios only.
|
|
1136
|
+
public struct MarkCompleteRequest: Codable, Equatable, Sendable {
|
|
1137
|
+
public var id: String
|
|
1138
|
+
public var at: String?
|
|
1139
|
+
|
|
1140
|
+
public init(id: String, at: String? = nil) {
|
|
1141
|
+
self.id = id
|
|
1142
|
+
self.at = at
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
public struct BoolResult: Codable, Equatable, Sendable {
|
|
1147
|
+
public var value: Bool
|
|
1148
|
+
|
|
1149
|
+
public init(value: Bool) {
|
|
1150
|
+
self.value = value
|
|
1151
|
+
}
|
|
1152
|
+
}
|
|
1153
|
+
|
|
1154
|
+
public struct StatusResult: Codable, Equatable, Sendable {
|
|
1155
|
+
public var status: PermissionStatus
|
|
1156
|
+
|
|
1157
|
+
public init(status: PermissionStatus) {
|
|
1158
|
+
self.status = status
|
|
1159
|
+
}
|
|
1160
|
+
}
|
|
1161
|
+
|
|
1162
|
+
/// Available on android only.
|
|
1163
|
+
public struct StatusesResult: Codable, Equatable, Sendable {
|
|
1164
|
+
public var statuses: [DataCategory: PermissionStatus]?
|
|
1165
|
+
|
|
1166
|
+
public init(statuses: [DataCategory: PermissionStatus]? = nil) {
|
|
1167
|
+
self.statuses = statuses
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
|
|
1171
|
+
public struct RecordIdList: Codable, Equatable, Sendable {
|
|
1172
|
+
public var ids: [String]
|
|
1173
|
+
|
|
1174
|
+
public init(ids: [String]) {
|
|
1175
|
+
self.ids = ids
|
|
1176
|
+
}
|
|
1177
|
+
}
|
|
1178
|
+
|
|
1179
|
+
public struct ConnectionList: Codable, Equatable, Sendable {
|
|
1180
|
+
public var connections: [Connection]
|
|
1181
|
+
|
|
1182
|
+
public init(connections: [Connection]) {
|
|
1183
|
+
self.connections = connections
|
|
1184
|
+
}
|
|
1185
|
+
}
|
|
1186
|
+
|
|
1187
|
+
public struct HeartRateList: Codable, Equatable, Sendable {
|
|
1188
|
+
public var samples: [HeartRateSample]
|
|
1189
|
+
|
|
1190
|
+
public init(samples: [HeartRateSample]) {
|
|
1191
|
+
self.samples = samples
|
|
1192
|
+
}
|
|
1193
|
+
}
|
|
1194
|
+
|
|
1195
|
+
public struct StepCountList: Codable, Equatable, Sendable {
|
|
1196
|
+
public var samples: [StepCount]
|
|
1197
|
+
|
|
1198
|
+
public init(samples: [StepCount]) {
|
|
1199
|
+
self.samples = samples
|
|
1200
|
+
}
|
|
1201
|
+
}
|
|
1202
|
+
|
|
1203
|
+
public struct SleepSegmentList: Codable, Equatable, Sendable {
|
|
1204
|
+
public var samples: [SleepSegment]
|
|
1205
|
+
|
|
1206
|
+
public init(samples: [SleepSegment]) {
|
|
1207
|
+
self.samples = samples
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
|
|
1211
|
+
public struct WorkoutList: Codable, Equatable, Sendable {
|
|
1212
|
+
public var samples: [Workout]
|
|
1213
|
+
|
|
1214
|
+
public init(samples: [Workout]) {
|
|
1215
|
+
self.samples = samples
|
|
1216
|
+
}
|
|
1217
|
+
}
|
|
1218
|
+
|
|
1219
|
+
/// Available on ios only.
|
|
1220
|
+
public struct PlannedWorkoutList: Codable, Equatable, Sendable {
|
|
1221
|
+
public var workouts: [PlannedWorkout]
|
|
1222
|
+
|
|
1223
|
+
public init(workouts: [PlannedWorkout]) {
|
|
1224
|
+
self.workouts = workouts
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
/// Once authorized, every sync run keeps the Watch schedule in step with Terra.
|
|
1229
|
+
///
|
|
1230
|
+
/// Available on ios only.
|
|
1231
|
+
public struct WorkoutScheduling: Codable, Equatable, Sendable {
|
|
1232
|
+
public var status: WorkoutSchedulingStatus
|
|
1233
|
+
|
|
1234
|
+
public init(status: WorkoutSchedulingStatus) {
|
|
1235
|
+
self.status = status
|
|
1236
|
+
}
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
public struct LastDeliveryResult: Codable, Equatable, Sendable {
|
|
1240
|
+
public var at: String?
|
|
1241
|
+
|
|
1242
|
+
public init(at: String? = nil) {
|
|
1243
|
+
self.at = at
|
|
1244
|
+
}
|
|
1245
|
+
}
|
|
1246
|
+
|
|
1247
|
+
public struct HeartRateEntryList: Codable, Equatable, Sendable {
|
|
1248
|
+
public var entries: [HeartRateEntry]
|
|
1249
|
+
|
|
1250
|
+
public init(entries: [HeartRateEntry]) {
|
|
1251
|
+
self.entries = entries
|
|
1252
|
+
}
|
|
1253
|
+
}
|
|
1254
|
+
|
|
1255
|
+
public struct BodyEntryList: Codable, Equatable, Sendable {
|
|
1256
|
+
public var entries: [BodyEntry]
|
|
1257
|
+
|
|
1258
|
+
public init(entries: [BodyEntry]) {
|
|
1259
|
+
self.entries = entries
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
|
|
1263
|
+
public struct StepEntryList: Codable, Equatable, Sendable {
|
|
1264
|
+
public var entries: [StepEntry]
|
|
1265
|
+
|
|
1266
|
+
public init(entries: [StepEntry]) {
|
|
1267
|
+
self.entries = entries
|
|
1268
|
+
}
|
|
1269
|
+
}
|
|
1270
|
+
|
|
1271
|
+
public struct SleepEntryList: Codable, Equatable, Sendable {
|
|
1272
|
+
public var entries: [SleepEntry]
|
|
1273
|
+
|
|
1274
|
+
public init(entries: [SleepEntry]) {
|
|
1275
|
+
self.entries = entries
|
|
1276
|
+
}
|
|
1277
|
+
}
|
|
1278
|
+
|
|
1279
|
+
public struct WorkoutEntryList: Codable, Equatable, Sendable {
|
|
1280
|
+
public var entries: [WorkoutEntry]
|
|
1281
|
+
|
|
1282
|
+
public init(entries: [WorkoutEntry]) {
|
|
1283
|
+
self.entries = entries
|
|
1284
|
+
}
|
|
1285
|
+
}
|
|
1286
|
+
|
|
1287
|
+
public struct NutritionEntryList: Codable, Equatable, Sendable {
|
|
1288
|
+
public var entries: [NutritionEntry]
|
|
1289
|
+
|
|
1290
|
+
public init(entries: [NutritionEntry]) {
|
|
1291
|
+
self.entries = entries
|
|
1292
|
+
}
|
|
1293
|
+
}
|
|
1294
|
+
|
|
1295
|
+
public enum TerraEventEnvelope {
|
|
1296
|
+
public static func validate(_ value: TerraEvent) throws {
|
|
1297
|
+
guard case .string = value.storage["at"] else {
|
|
1298
|
+
throw DecodingError.dataCorrupted(
|
|
1299
|
+
.init(codingPath: [], debugDescription: "TerraEvent.at is not a string")
|
|
1300
|
+
)
|
|
1301
|
+
}
|
|
1302
|
+
guard case .string = value.storage["event"] else {
|
|
1303
|
+
throw DecodingError.dataCorrupted(
|
|
1304
|
+
.init(codingPath: [], debugDescription: "TerraEvent.event is not a string")
|
|
1305
|
+
)
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
public enum SupportReportEnvelope {
|
|
1311
|
+
public static func validate(_ value: SupportReport) throws {
|
|
1312
|
+
for level0 in value.recentEvents {
|
|
1313
|
+
try TerraEventEnvelope.validate(level0)
|
|
1314
|
+
}
|
|
1315
|
+
}
|
|
1316
|
+
}
|
|
1317
|
+
|