@kingstinct/react-native-healthkit 14.0.1 → 14.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.
Files changed (30) hide show
  1. package/app.plugin.js +13 -7
  2. package/app.plugin.ts +39 -15
  3. package/ios/BackgroundDeliveryManager.swift +82 -1
  4. package/ios/CoreModule.swift +59 -17
  5. package/ios/ExceptionCatcher.h +1 -0
  6. package/ios/ExceptionCatcher.mm +15 -0
  7. package/ios/WorkoutProxy.swift +13 -1
  8. package/lib/commonjs/generated/healthkit.generated.js +2 -0
  9. package/lib/module/generated/healthkit.generated.js +2 -0
  10. package/lib/typescript/generated/healthkit.generated.d.ts +4 -1
  11. package/lib/typescript/types/Units.d.ts +1 -1
  12. package/lib/typescript/types/Workouts.d.ts +1 -0
  13. package/nitrogen/generated/ios/swift/ObjectTypeIdentifier.swift +4 -0
  14. package/nitrogen/generated/ios/swift/QuantityTypeIdentifier.swift +4 -0
  15. package/nitrogen/generated/ios/swift/QuantityTypeIdentifierWriteable.swift +4 -0
  16. package/nitrogen/generated/ios/swift/SampleTypeIdentifier.swift +4 -0
  17. package/nitrogen/generated/ios/swift/SampleTypeIdentifierWriteable.swift +4 -0
  18. package/nitrogen/generated/ios/swift/WorkoutActivity.swift +7 -2
  19. package/nitrogen/generated/shared/c++/ObjectTypeIdentifier.hpp +118 -114
  20. package/nitrogen/generated/shared/c++/QuantityTypeIdentifier.hpp +111 -107
  21. package/nitrogen/generated/shared/c++/QuantityTypeIdentifierWriteable.hpp +111 -107
  22. package/nitrogen/generated/shared/c++/SampleTypeIdentifier.hpp +117 -113
  23. package/nitrogen/generated/shared/c++/SampleTypeIdentifierWriteable.hpp +116 -112
  24. package/nitrogen/generated/shared/c++/WorkoutActivity.hpp +9 -3
  25. package/package.json +1 -1
  26. package/src/generated/healthkit-schema.json +13 -5
  27. package/src/generated/healthkit.generated.ts +4 -0
  28. package/src/type-tests/generated-typing.ts +14 -0
  29. package/src/types/Units.ts +1 -1
  30. package/src/types/Workouts.ts +1 -0
package/app.plugin.js CHANGED
@@ -53,20 +53,26 @@ const withEntitlementsPlugin = (
53
53
  const withInfoPlistPlugin = (
54
54
  config,
55
55
  /**
56
- * @type {{NSHealthShareUsageDescription: string | true, NSHealthUpdateUsageDescription: string | true} | undefined}
56
+ * @type {{NSHealthShareUsageDescription?: string | true, NSHealthUpdateUsageDescription?: string | false} | undefined}
57
57
  * */
58
58
  props,
59
59
  ) =>
60
60
  withInfoPlist(config, (config) => {
61
61
  config.modResults.NSHealthShareUsageDescription =
62
- typeof props.NSHealthShareUsageDescription === 'string'
62
+ typeof props?.NSHealthShareUsageDescription === 'string'
63
63
  ? props.NSHealthShareUsageDescription
64
- : `${config.name} wants to read your health data`
64
+ : typeof config.modResults.NSHealthShareUsageDescription === 'string'
65
+ ? config.modResults.NSHealthShareUsageDescription
66
+ : `${config.name} wants to read your health data`
65
67
 
66
- config.modResults.NSHealthUpdateUsageDescription =
67
- typeof props.NSHealthUpdateUsageDescription === 'string'
68
- ? props.NSHealthUpdateUsageDescription
69
- : `${config.name} wants to update your health data`
68
+ if (props?.NSHealthUpdateUsageDescription !== false) {
69
+ config.modResults.NSHealthUpdateUsageDescription =
70
+ typeof props?.NSHealthUpdateUsageDescription === 'string'
71
+ ? props.NSHealthUpdateUsageDescription
72
+ : typeof config.modResults.NSHealthUpdateUsageDescription === 'string'
73
+ ? config.modResults.NSHealthUpdateUsageDescription
74
+ : `${config.name} wants to update your health data`
75
+ }
70
76
 
71
77
  return config
72
78
  })
package/app.plugin.ts CHANGED
@@ -13,7 +13,7 @@ type BackgroundConfig = boolean
13
13
 
14
14
  type InfoPlistConfig = {
15
15
  NSHealthShareUsageDescription?: string | true
16
- NSHealthUpdateUsageDescription?: string | true
16
+ NSHealthUpdateUsageDescription?: string | false
17
17
  }
18
18
 
19
19
  type AppPluginConfig = InfoPlistConfig & {
@@ -40,17 +40,25 @@ const withEntitlementsPlugin: ConfigPlugin<{
40
40
 
41
41
  const withInfoPlistPlugin: ConfigPlugin<InfoPlistConfig> = (config, props) => {
42
42
  return withInfoPlist(config, (configPlist) => {
43
+ const existingShareDescription =
44
+ configPlist.modResults.NSHealthShareUsageDescription
43
45
  configPlist.modResults.NSHealthShareUsageDescription =
44
- typeof props.NSHealthShareUsageDescription === 'string'
46
+ typeof props?.NSHealthShareUsageDescription === 'string'
45
47
  ? props.NSHealthShareUsageDescription
46
- : `${config.name ?? pkg.name} wants to read your health data`
47
-
48
- // Add description if it's not undefined and not explicitly false
49
-
50
- configPlist.modResults.NSHealthUpdateUsageDescription =
51
- typeof props.NSHealthUpdateUsageDescription === 'string'
52
- ? props.NSHealthUpdateUsageDescription
53
- : `${config.name ?? pkg.name} wants to update your health data`
48
+ : typeof existingShareDescription === 'string'
49
+ ? existingShareDescription
50
+ : `${config.name ?? pkg.name} wants to read your health data`
51
+
52
+ if (props?.NSHealthUpdateUsageDescription !== false) {
53
+ const existingUpdateDescription =
54
+ configPlist.modResults.NSHealthUpdateUsageDescription
55
+ configPlist.modResults.NSHealthUpdateUsageDescription =
56
+ typeof props?.NSHealthUpdateUsageDescription === 'string'
57
+ ? props.NSHealthUpdateUsageDescription
58
+ : typeof existingUpdateDescription === 'string'
59
+ ? existingUpdateDescription
60
+ : `${config.name ?? pkg.name} wants to update your health data`
61
+ }
54
62
 
55
63
  return configPlist
56
64
  })
@@ -82,12 +90,28 @@ const withAppDelegatePlugin: ConfigPlugin<{
82
90
  if (
83
91
  !configDelegate.modResults.contents.includes('BackgroundDeliveryManager')
84
92
  ) {
85
- // Match the opening of didFinishLaunchingWithOptions and insert after the opening brace
86
- configDelegate.modResults.contents =
87
- configDelegate.modResults.contents.replace(
88
- /(func application\(.+didFinishLaunchingWithOptions.+\{)\n/,
89
- `$1\n${setupCall}`,
93
+ // Match the opening of didFinishLaunchingWithOptions and insert after the
94
+ // opening brace. `[^{]*` rather than `.+` for two reasons: `.` does not
95
+ // match newlines, and Expo SDK 54+ templates spread this signature over
96
+ // several lines; and refusing to cross a `{` keeps the match from
97
+ // spanning out of an earlier `application(...)` overload into this one.
98
+ const withSetup = configDelegate.modResults.contents.replace(
99
+ /(func application\([^{]*didFinishLaunchingWithOptions[^{]*\{)\n/,
100
+ `$1\n${setupCall}`,
101
+ )
102
+
103
+ if (withSetup === configDelegate.modResults.contents) {
104
+ // Don't fail the build, but don't fail silently either — background
105
+ // delivery just won't survive app termination, which is otherwise
106
+ // very hard to trace back to here.
107
+ console.warn(
108
+ '[react-native-healthkit] Could not find didFinishLaunchingWithOptions in AppDelegate; ' +
109
+ 'BackgroundDeliveryManager.shared.setupBackgroundObservers() was not inserted. ' +
110
+ 'HealthKit background delivery will not work until it is added manually.',
90
111
  )
112
+ }
113
+
114
+ configDelegate.modResults.contents = withSetup
91
115
  }
92
116
 
93
117
  return configDelegate
@@ -1,5 +1,8 @@
1
1
  import Foundation
2
2
  import HealthKit
3
+ import os.log
4
+
5
+ private let bgLog = OSLog(subsystem: "com.kingstinct.healthkit", category: "BackgroundDelivery")
3
6
 
4
7
  /// Manages HealthKit background delivery by registering observer queries at app launch,
5
8
  /// before the JS bridge is available. This is required by Apple — observer queries must
@@ -20,6 +23,11 @@ import HealthKit
20
23
  private var observerQueries: [String: HKObserverQuery] = [:]
21
24
  private var pendingEvents: [(typeIdentifier: String, errorMessage: String?)] = []
22
25
  private var jsCallback: ((String, String?) -> Void)?
26
+ // Per-type callbacks, checked before the global `jsCallback` above. Lets
27
+ // CoreModule.subscribeToObserverQuery route a JS subscription for a
28
+ // background-configured type through this manager's already-running
29
+ // HKObserverQuery instead of registering a second, independent one.
30
+ private var typeCallbacks: [String: (String, String?) -> Void] = [:]
23
31
  private var isSetUp = false
24
32
 
25
33
  static let typesKey = "com.kingstinct.healthkit.backgroundTypes"
@@ -85,6 +93,37 @@ import HealthKit
85
93
  }
86
94
  }
87
95
 
96
+ /// Subscribe a JS callback for a specific type. Any events for this type
97
+ /// that arrived before JS subscribed (e.g. from a background wake, queued
98
+ /// in `pendingEvents` above) are flushed immediately.
99
+ func setCallback(typeIdentifier: String, callback: @escaping (String, String?) -> Void) {
100
+ queue.sync(flags: .barrier) {
101
+ self.typeCallbacks[typeIdentifier] = callback
102
+ let matching = self.pendingEvents.filter { $0.typeIdentifier == typeIdentifier }
103
+ self.pendingEvents.removeAll { $0.typeIdentifier == typeIdentifier }
104
+ for event in matching {
105
+ callback(typeIdentifier, event.errorMessage)
106
+ }
107
+ }
108
+ }
109
+
110
+ /// Remove the per-type JS callback (e.g., on unsubscribe).
111
+ func removeCallback(typeIdentifier: String) {
112
+ queue.sync(flags: .barrier) {
113
+ self.typeCallbacks.removeValue(forKey: typeIdentifier)
114
+ }
115
+ }
116
+
117
+ /// True if `typeIdentifier` has a native HKObserverQuery registered by
118
+ /// `registerObservers` — i.e. background delivery is configured for it.
119
+ /// CoreModule.subscribeToObserverQuery checks this before deciding whether
120
+ /// to reuse this manager's observer or register its own.
121
+ func isBackgroundConfigured(typeIdentifier: String) -> Bool {
122
+ return queue.sync {
123
+ self.observerQueries[typeIdentifier] != nil
124
+ }
125
+ }
126
+
88
127
  /// Stop all observer queries and clear state.
89
128
  func tearDown() {
90
129
  queue.sync(flags: .barrier) {
@@ -92,6 +131,7 @@ import HealthKit
92
131
  self.healthStore.stop(query)
93
132
  }
94
133
  self.observerQueries = [:]
134
+ self.typeCallbacks = [:]
95
135
  self.isSetUp = false
96
136
  }
97
137
  }
@@ -121,6 +161,11 @@ import HealthKit
121
161
  sampleType: sampleType,
122
162
  predicate: nil
123
163
  ) { [weak self] (_: HKObserverQuery, completionHandler: @escaping HKObserverQueryCompletionHandler, error: Error?) in
164
+ // handleObserverCallback opens a beginBackgroundTask() window as its
165
+ // first, synchronous action, before this returns to call
166
+ // completionHandler() — otherwise iOS is free to suspend the process
167
+ // the moment HealthKit's own completion handler fires, possibly
168
+ // before Hermes has finished booting to run the JS callback.
124
169
  self?.handleObserverCallback(
125
170
  typeIdentifier: typeIdentifier,
126
171
  error: error
@@ -147,18 +192,54 @@ import HealthKit
147
192
 
148
193
  private func handleObserverCallback(typeIdentifier: String, error: Error?) {
149
194
  let errorMessage = error?.localizedDescription
195
+ os_log("observer fired: %{public}@", log: bgLog, type: .info, typeIdentifier)
196
+
197
+ // Ask iOS for real execution time before doing anything else, so the
198
+ // process survives long enough for Hermes to boot and the JS callback to
199
+ // run — see the comment at this query's registration above.
200
+ var backgroundTaskId = UIBackgroundTaskIdentifier.invalid
201
+ let endTask: () -> Void = { [weak self] in
202
+ self?.queue.sync(flags: .barrier) {
203
+ guard backgroundTaskId != .invalid else { return }
204
+ UIApplication.shared.endBackgroundTask(backgroundTaskId)
205
+ backgroundTaskId = .invalid
206
+ }
207
+ }
208
+ backgroundTaskId = UIApplication.shared.beginBackgroundTask(withName: "healthkit-observer-\(typeIdentifier)") {
209
+ os_log("background task expired: %{public}@", log: bgLog, type: .info, typeIdentifier)
210
+ endTask()
211
+ }
212
+ os_log("background task started: %{public}@", log: bgLog, type: .info, typeIdentifier)
150
213
 
151
214
  queue.sync(flags: .barrier) {
152
- if let callback = self.jsCallback {
215
+ if let callback = self.typeCallbacks[typeIdentifier] {
216
+ DispatchQueue.main.async {
217
+ os_log("dispatching to per-type JS callback: %{public}@", log: bgLog, type: .info, typeIdentifier)
218
+ callback(typeIdentifier, errorMessage)
219
+ }
220
+ } else if let callback = self.jsCallback {
153
221
  // JS is connected — dispatch to main thread for JSI safety
154
222
  DispatchQueue.main.async {
223
+ os_log("dispatching to global JS callback: %{public}@", log: bgLog, type: .info, typeIdentifier)
155
224
  callback(typeIdentifier, errorMessage)
156
225
  }
157
226
  } else {
158
227
  // JS not ready yet — queue the event for later
228
+ os_log("no JS callback yet, queuing: %{public}@", log: bgLog, type: .info, typeIdentifier)
159
229
  self.pendingEvents.append((typeIdentifier: typeIdentifier, errorMessage: errorMessage))
160
230
  }
161
231
  }
232
+
233
+ // Hold the task open for a fixed, generous window rather than trying to
234
+ // ack precisely when JS finishes — Hermes boot plus the JS callback's own
235
+ // async work (HealthKit reads + Supabase upsert) is unpredictable, and a
236
+ // completion-ack channel back from JS isn't worth building on the first
237
+ // pass for a personal-use app. First place to revisit if verification
238
+ // shows this window is too tight.
239
+ DispatchQueue.main.asyncAfter(deadline: .now() + 25) {
240
+ os_log("background task window elapsed: %{public}@", log: bgLog, type: .info, typeIdentifier)
241
+ endTask()
242
+ }
162
243
  }
163
244
 
164
245
  // Local type resolution that doesn't depend on NitroModules (which isn't available at AppDelegate time).
@@ -157,21 +157,27 @@ class CoreModule: HybridCoreModuleSpec {
157
157
  returning: .unnecessary
158
158
  )
159
159
  }
160
- return store.getRequestStatusForAuthorization(toShare: toShare, read: toRead) {
161
- status, error in
162
- DispatchQueue.main.async {
163
- if let error = error {
164
- continuation.resume(throwing: error)
165
- } else {
166
- if let authStatus = AuthorizationRequestStatus(rawValue: Int32(status.rawValue)) {
167
- continuation.resume(returning: authStatus)
160
+ var caughtError: NSError?
161
+ let started = RunBlockCatchingObjCExceptions({
162
+ store.getRequestStatusForAuthorization(toShare: toShare, read: toRead) {
163
+ status, error in
164
+ DispatchQueue.main.async {
165
+ if let error = error {
166
+ continuation.resume(throwing: error)
168
167
  } else {
169
- continuation.resume(
170
- throwing: runtimeErrorWithPrefix(
171
- "Unrecognized authStatus returned: \(status.rawValue)"))
168
+ if let authStatus = AuthorizationRequestStatus(rawValue: Int32(status.rawValue)) {
169
+ continuation.resume(returning: authStatus)
170
+ } else {
171
+ continuation.resume(
172
+ throwing: runtimeErrorWithPrefix(
173
+ "Unrecognized authStatus returned: \(status.rawValue)"))
174
+ }
172
175
  }
173
176
  }
174
177
  }
178
+ }, &caughtError)
179
+ if !started, let caughtError {
180
+ continuation.resume(throwing: caughtError)
175
181
  }
176
182
  }
177
183
  }
@@ -183,14 +189,20 @@ class CoreModule: HybridCoreModuleSpec {
183
189
  let toRead = objectTypesFromArray(typeIdentifiers: toRequest.toRead ?? [])
184
190
 
185
191
  return try await withCheckedThrowingContinuation { continuation in
186
- store.requestAuthorization(toShare: share, read: toRead) { status, error in
187
- DispatchQueue.main.async {
188
- if let error = error {
189
- continuation.resume(throwing: error)
190
- } else {
191
- continuation.resume(returning: status)
192
+ var caughtError: NSError?
193
+ let started = RunBlockCatchingObjCExceptions({
194
+ store.requestAuthorization(toShare: share, read: toRead) { status, error in
195
+ DispatchQueue.main.async {
196
+ if let error = error {
197
+ continuation.resume(throwing: error)
198
+ } else {
199
+ continuation.resume(returning: status)
200
+ }
192
201
  }
193
202
  }
203
+ }, &caughtError)
204
+ if !started, let caughtError {
205
+ continuation.resume(throwing: caughtError)
194
206
  }
195
207
  }
196
208
  }
@@ -349,6 +361,10 @@ class CoreModule: HybridCoreModuleSpec {
349
361
  }
350
362
 
351
363
  var _runningQueries: [String: HKQuery] = [:]
364
+ // queryId -> typeIdentifier for subscriptions routed through
365
+ // BackgroundDeliveryManager instead of getting their own HKObserverQuery
366
+ // (see subscribeToObserverQuery below).
367
+ var _backgroundRoutedQueries: [String: String] = [:]
352
368
 
353
369
  func deleteObjects(objectTypeIdentifier: SampleTypeIdentifierWriteable, filter: FilterForSamples)
354
370
  -> Promise<Double> {
@@ -377,6 +393,25 @@ class CoreModule: HybridCoreModuleSpec {
377
393
  typeIdentifier: SampleTypeIdentifier,
378
394
  callback: @escaping (OnChangeCallbackArgs) -> Void
379
395
  ) throws -> String {
396
+ let typeIdString = typeIdentifier.stringValue
397
+
398
+ if BackgroundDeliveryManager.shared.isBackgroundConfigured(typeIdentifier: typeIdString) {
399
+ // BackgroundDeliveryManager already has an HKObserverQuery running for
400
+ // this type (registered at launch, survives termination) — route
401
+ // through it instead of registering a second, independent observer for
402
+ // the same type.
403
+ let queryId = UUID().uuidString
404
+ BackgroundDeliveryManager.shared.setCallback(typeIdentifier: typeIdString) {
405
+ (_, errorMessage) in
406
+ DispatchQueue.main.async {
407
+ callback(
408
+ OnChangeCallbackArgs(typeIdentifier: typeIdentifier, errorMessage: errorMessage))
409
+ }
410
+ }
411
+ self._backgroundRoutedQueries[queryId] = typeIdString
412
+ return queryId
413
+ }
414
+
380
415
  let sampleType = try sampleTypeFrom(sampleTypeIdentifier: typeIdentifier)
381
416
 
382
417
  let predicate = HKQuery.predicateForSamples(
@@ -411,6 +446,13 @@ class CoreModule: HybridCoreModuleSpec {
411
446
  }
412
447
 
413
448
  func unsubscribeQuery(queryId: String) throws -> Bool {
449
+ if let typeIdString = self._backgroundRoutedQueries[queryId] {
450
+ BackgroundDeliveryManager.shared.removeCallback(typeIdentifier: typeIdString)
451
+ self._backgroundRoutedQueries.removeValue(forKey: queryId)
452
+
453
+ return true
454
+ }
455
+
414
456
  guard let query = self._runningQueries[queryId] else {
415
457
  warnWithPrefix("unsubscribeQuery: Query with id \(queryId) not found")
416
458
 
@@ -2,3 +2,4 @@
2
2
  #import <HealthKit/HealthKit.h>
3
3
 
4
4
  HKUnit * _Nullable HKUnitFromStringCatchingExceptions(NSString * _Nonnull unitString, NSError * _Nullable * _Nullable outError);
5
+ BOOL RunBlockCatchingObjCExceptions(void (NS_NOESCAPE ^_Nonnull block)(void), NSError * _Nullable * _Nullable outError);
@@ -15,3 +15,18 @@ HKUnit * _Nullable HKUnitFromStringCatchingExceptions(NSString * _Nonnull unitSt
15
15
  return nil;
16
16
  }
17
17
  }
18
+
19
+ BOOL RunBlockCatchingObjCExceptions(void (NS_NOESCAPE ^block)(void), NSError * _Nullable * _Nullable outError) {
20
+ if (outError) { *outError = nil; }
21
+ @try {
22
+ block();
23
+ return YES;
24
+ }
25
+ @catch (NSException *exception) {
26
+ if (outError) {
27
+ NSDictionary *userInfo = exception.userInfo ?: @{};
28
+ *outError = [NSError errorWithDomain:exception.name code:0 userInfo:userInfo];
29
+ }
30
+ return NO;
31
+ }
32
+ }
@@ -370,11 +370,23 @@ class WorkoutProxy: HybridWorkoutProxySpec {
370
370
  let hkActivities = workout.workoutActivities
371
371
 
372
372
  return hkActivities.map { activity in
373
+ let rawActivityType = activity.workoutConfiguration.activityType.rawValue
374
+ let activityType = Int32(exactly: rawActivityType).flatMap {
375
+ WorkoutActivityType.init(rawValue: $0)
376
+ }
377
+
378
+ if activityType == nil {
379
+ warnWithPrefix(
380
+ "Unknown workoutActivityType with rawValue: \(rawActivityType), falling back to 'other'"
381
+ )
382
+ }
383
+
373
384
  return WorkoutActivity(
374
385
  startDate: activity.startDate,
375
386
  endDate: activity.endDate ?? activity.startDate,
376
387
  uuid: activity.uuid.uuidString,
377
- duration: activity.duration
388
+ duration: activity.duration,
389
+ activityType: activityType ?? WorkoutActivityType.other
378
390
  )
379
391
  }
380
392
  }
@@ -18,6 +18,7 @@ exports.QUANTITY_IDENTIFIER_IOS_AVAILABILITY = {
18
18
  HKQuantityTypeIdentifierBasalEnergyBurned: '8.0',
19
19
  HKQuantityTypeIdentifierBloodAlcoholContent: '8.0',
20
20
  HKQuantityTypeIdentifierBloodGlucose: '8.0',
21
+ HKQuantityTypeIdentifierBloodKetones: '8.0',
21
22
  HKQuantityTypeIdentifierBloodPressureDiastolic: '8.0',
22
23
  HKQuantityTypeIdentifierBloodPressureSystolic: '8.0',
23
24
  HKQuantityTypeIdentifierBodyFatPercentage: '8.0',
@@ -212,6 +213,7 @@ exports.QUANTITY_IDENTIFIER_CANONICAL_UNITS = {
212
213
  HKQuantityTypeIdentifierBasalEnergyBurned: 'kcal',
213
214
  HKQuantityTypeIdentifierBloodAlcoholContent: '%',
214
215
  HKQuantityTypeIdentifierBloodGlucose: 'mg/dL',
216
+ HKQuantityTypeIdentifierBloodKetones: 'mmol/L',
215
217
  HKQuantityTypeIdentifierBloodPressureDiastolic: 'mmHg',
216
218
  HKQuantityTypeIdentifierBloodPressureSystolic: 'mmHg',
217
219
  HKQuantityTypeIdentifierBodyFatPercentage: '%',
@@ -15,6 +15,7 @@ export const QUANTITY_IDENTIFIER_IOS_AVAILABILITY = {
15
15
  HKQuantityTypeIdentifierBasalEnergyBurned: '8.0',
16
16
  HKQuantityTypeIdentifierBloodAlcoholContent: '8.0',
17
17
  HKQuantityTypeIdentifierBloodGlucose: '8.0',
18
+ HKQuantityTypeIdentifierBloodKetones: '8.0',
18
19
  HKQuantityTypeIdentifierBloodPressureDiastolic: '8.0',
19
20
  HKQuantityTypeIdentifierBloodPressureSystolic: '8.0',
20
21
  HKQuantityTypeIdentifierBodyFatPercentage: '8.0',
@@ -209,6 +210,7 @@ export const QUANTITY_IDENTIFIER_CANONICAL_UNITS = {
209
210
  HKQuantityTypeIdentifierBasalEnergyBurned: 'kcal',
210
211
  HKQuantityTypeIdentifierBloodAlcoholContent: '%',
211
212
  HKQuantityTypeIdentifierBloodGlucose: 'mg/dL',
213
+ HKQuantityTypeIdentifierBloodKetones: 'mmol/L',
212
214
  HKQuantityTypeIdentifierBloodPressureDiastolic: 'mmHg',
213
215
  HKQuantityTypeIdentifierBloodPressureSystolic: 'mmHg',
214
216
  HKQuantityTypeIdentifierBodyFatPercentage: '%',
@@ -1,7 +1,7 @@
1
1
  import type { Quantity } from '../types/QuantityType';
2
2
  import type { BloodGlucoseUnit, CountPerTime, EnergyUnit, LengthUnit, MassUnit, PressureUnit, SpeedUnit, TemperatureUnit, TimeUnit } from '../types/Units';
3
3
  export type QuantityTypeIdentifierReadOnly = 'HKQuantityTypeIdentifierAppleExerciseTime' | 'HKQuantityTypeIdentifierAppleStandTime' | 'HKQuantityTypeIdentifierAppleWalkingSteadiness' | 'HKQuantityTypeIdentifierAtrialFibrillationBurden' | 'HKQuantityTypeIdentifierWalkingHeartRateAverage';
4
- export type QuantityTypeIdentifierWriteable = 'HKQuantityTypeIdentifierActiveEnergyBurned' | 'HKQuantityTypeIdentifierAppleMoveTime' | 'HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances' | 'HKQuantityTypeIdentifierAppleSleepingWristTemperature' | 'HKQuantityTypeIdentifierBasalBodyTemperature' | 'HKQuantityTypeIdentifierBasalEnergyBurned' | 'HKQuantityTypeIdentifierBloodAlcoholContent' | 'HKQuantityTypeIdentifierBloodGlucose' | 'HKQuantityTypeIdentifierBloodPressureDiastolic' | 'HKQuantityTypeIdentifierBloodPressureSystolic' | 'HKQuantityTypeIdentifierBodyFatPercentage' | 'HKQuantityTypeIdentifierBodyMass' | 'HKQuantityTypeIdentifierBodyMassIndex' | 'HKQuantityTypeIdentifierBodyTemperature' | 'HKQuantityTypeIdentifierCrossCountrySkiingSpeed' | 'HKQuantityTypeIdentifierCyclingCadence' | 'HKQuantityTypeIdentifierCyclingFunctionalThresholdPower' | 'HKQuantityTypeIdentifierCyclingPower' | 'HKQuantityTypeIdentifierCyclingSpeed' | 'HKQuantityTypeIdentifierDietaryBiotin' | 'HKQuantityTypeIdentifierDietaryCaffeine' | 'HKQuantityTypeIdentifierDietaryCalcium' | 'HKQuantityTypeIdentifierDietaryCarbohydrates' | 'HKQuantityTypeIdentifierDietaryChloride' | 'HKQuantityTypeIdentifierDietaryCholesterol' | 'HKQuantityTypeIdentifierDietaryChromium' | 'HKQuantityTypeIdentifierDietaryCopper' | 'HKQuantityTypeIdentifierDietaryEnergyConsumed' | 'HKQuantityTypeIdentifierDietaryFatMonounsaturated' | 'HKQuantityTypeIdentifierDietaryFatPolyunsaturated' | 'HKQuantityTypeIdentifierDietaryFatSaturated' | 'HKQuantityTypeIdentifierDietaryFatTotal' | 'HKQuantityTypeIdentifierDietaryFiber' | 'HKQuantityTypeIdentifierDietaryFolate' | 'HKQuantityTypeIdentifierDietaryIodine' | 'HKQuantityTypeIdentifierDietaryIron' | 'HKQuantityTypeIdentifierDietaryMagnesium' | 'HKQuantityTypeIdentifierDietaryManganese' | 'HKQuantityTypeIdentifierDietaryMolybdenum' | 'HKQuantityTypeIdentifierDietaryNiacin' | 'HKQuantityTypeIdentifierDietaryPantothenicAcid' | 'HKQuantityTypeIdentifierDietaryPhosphorus' | 'HKQuantityTypeIdentifierDietaryPotassium' | 'HKQuantityTypeIdentifierDietaryProtein' | 'HKQuantityTypeIdentifierDietaryRiboflavin' | 'HKQuantityTypeIdentifierDietarySelenium' | 'HKQuantityTypeIdentifierDietarySodium' | 'HKQuantityTypeIdentifierDietarySugar' | 'HKQuantityTypeIdentifierDietaryThiamin' | 'HKQuantityTypeIdentifierDietaryVitaminA' | 'HKQuantityTypeIdentifierDietaryVitaminB12' | 'HKQuantityTypeIdentifierDietaryVitaminB6' | 'HKQuantityTypeIdentifierDietaryVitaminC' | 'HKQuantityTypeIdentifierDietaryVitaminD' | 'HKQuantityTypeIdentifierDietaryVitaminE' | 'HKQuantityTypeIdentifierDietaryVitaminK' | 'HKQuantityTypeIdentifierDietaryWater' | 'HKQuantityTypeIdentifierDietaryZinc' | 'HKQuantityTypeIdentifierDistanceCrossCountrySkiing' | 'HKQuantityTypeIdentifierDistanceCycling' | 'HKQuantityTypeIdentifierDistanceDownhillSnowSports' | 'HKQuantityTypeIdentifierDistancePaddleSports' | 'HKQuantityTypeIdentifierDistanceRowing' | 'HKQuantityTypeIdentifierDistanceSkatingSports' | 'HKQuantityTypeIdentifierDistanceSwimming' | 'HKQuantityTypeIdentifierDistanceWalkingRunning' | 'HKQuantityTypeIdentifierDistanceWheelchair' | 'HKQuantityTypeIdentifierElectrodermalActivity' | 'HKQuantityTypeIdentifierEnvironmentalAudioExposure' | 'HKQuantityTypeIdentifierEnvironmentalSoundReduction' | 'HKQuantityTypeIdentifierEstimatedWorkoutEffortScore' | 'HKQuantityTypeIdentifierFlightsClimbed' | 'HKQuantityTypeIdentifierForcedExpiratoryVolume1' | 'HKQuantityTypeIdentifierForcedVitalCapacity' | 'HKQuantityTypeIdentifierHeadphoneAudioExposure' | 'HKQuantityTypeIdentifierHeartRate' | 'HKQuantityTypeIdentifierHeartRateRecoveryOneMinute' | 'HKQuantityTypeIdentifierHeartRateVariabilitySDNN' | 'HKQuantityTypeIdentifierHeight' | 'HKQuantityTypeIdentifierInhalerUsage' | 'HKQuantityTypeIdentifierInsulinDelivery' | 'HKQuantityTypeIdentifierLeanBodyMass' | 'HKQuantityTypeIdentifierNikeFuel' | 'HKQuantityTypeIdentifierNumberOfAlcoholicBeverages' | 'HKQuantityTypeIdentifierNumberOfTimesFallen' | 'HKQuantityTypeIdentifierOxygenSaturation' | 'HKQuantityTypeIdentifierPaddleSportsSpeed' | 'HKQuantityTypeIdentifierPeakExpiratoryFlowRate' | 'HKQuantityTypeIdentifierPeripheralPerfusionIndex' | 'HKQuantityTypeIdentifierPhysicalEffort' | 'HKQuantityTypeIdentifierPushCount' | 'HKQuantityTypeIdentifierRespiratoryRate' | 'HKQuantityTypeIdentifierRestingHeartRate' | 'HKQuantityTypeIdentifierRowingSpeed' | 'HKQuantityTypeIdentifierRunningGroundContactTime' | 'HKQuantityTypeIdentifierRunningPower' | 'HKQuantityTypeIdentifierRunningSpeed' | 'HKQuantityTypeIdentifierRunningStrideLength' | 'HKQuantityTypeIdentifierRunningVerticalOscillation' | 'HKQuantityTypeIdentifierSixMinuteWalkTestDistance' | 'HKQuantityTypeIdentifierStairAscentSpeed' | 'HKQuantityTypeIdentifierStairDescentSpeed' | 'HKQuantityTypeIdentifierStepCount' | 'HKQuantityTypeIdentifierSwimmingStrokeCount' | 'HKQuantityTypeIdentifierTimeInDaylight' | 'HKQuantityTypeIdentifierUnderwaterDepth' | 'HKQuantityTypeIdentifierUVExposure' | 'HKQuantityTypeIdentifierVO2Max' | 'HKQuantityTypeIdentifierWaistCircumference' | 'HKQuantityTypeIdentifierWalkingAsymmetryPercentage' | 'HKQuantityTypeIdentifierWalkingDoubleSupportPercentage' | 'HKQuantityTypeIdentifierWalkingSpeed' | 'HKQuantityTypeIdentifierWalkingStepLength' | 'HKQuantityTypeIdentifierWaterTemperature' | 'HKQuantityTypeIdentifierWorkoutEffortScore';
4
+ export type QuantityTypeIdentifierWriteable = 'HKQuantityTypeIdentifierActiveEnergyBurned' | 'HKQuantityTypeIdentifierAppleMoveTime' | 'HKQuantityTypeIdentifierAppleSleepingBreathingDisturbances' | 'HKQuantityTypeIdentifierAppleSleepingWristTemperature' | 'HKQuantityTypeIdentifierBasalBodyTemperature' | 'HKQuantityTypeIdentifierBasalEnergyBurned' | 'HKQuantityTypeIdentifierBloodAlcoholContent' | 'HKQuantityTypeIdentifierBloodGlucose' | 'HKQuantityTypeIdentifierBloodKetones' | 'HKQuantityTypeIdentifierBloodPressureDiastolic' | 'HKQuantityTypeIdentifierBloodPressureSystolic' | 'HKQuantityTypeIdentifierBodyFatPercentage' | 'HKQuantityTypeIdentifierBodyMass' | 'HKQuantityTypeIdentifierBodyMassIndex' | 'HKQuantityTypeIdentifierBodyTemperature' | 'HKQuantityTypeIdentifierCrossCountrySkiingSpeed' | 'HKQuantityTypeIdentifierCyclingCadence' | 'HKQuantityTypeIdentifierCyclingFunctionalThresholdPower' | 'HKQuantityTypeIdentifierCyclingPower' | 'HKQuantityTypeIdentifierCyclingSpeed' | 'HKQuantityTypeIdentifierDietaryBiotin' | 'HKQuantityTypeIdentifierDietaryCaffeine' | 'HKQuantityTypeIdentifierDietaryCalcium' | 'HKQuantityTypeIdentifierDietaryCarbohydrates' | 'HKQuantityTypeIdentifierDietaryChloride' | 'HKQuantityTypeIdentifierDietaryCholesterol' | 'HKQuantityTypeIdentifierDietaryChromium' | 'HKQuantityTypeIdentifierDietaryCopper' | 'HKQuantityTypeIdentifierDietaryEnergyConsumed' | 'HKQuantityTypeIdentifierDietaryFatMonounsaturated' | 'HKQuantityTypeIdentifierDietaryFatPolyunsaturated' | 'HKQuantityTypeIdentifierDietaryFatSaturated' | 'HKQuantityTypeIdentifierDietaryFatTotal' | 'HKQuantityTypeIdentifierDietaryFiber' | 'HKQuantityTypeIdentifierDietaryFolate' | 'HKQuantityTypeIdentifierDietaryIodine' | 'HKQuantityTypeIdentifierDietaryIron' | 'HKQuantityTypeIdentifierDietaryMagnesium' | 'HKQuantityTypeIdentifierDietaryManganese' | 'HKQuantityTypeIdentifierDietaryMolybdenum' | 'HKQuantityTypeIdentifierDietaryNiacin' | 'HKQuantityTypeIdentifierDietaryPantothenicAcid' | 'HKQuantityTypeIdentifierDietaryPhosphorus' | 'HKQuantityTypeIdentifierDietaryPotassium' | 'HKQuantityTypeIdentifierDietaryProtein' | 'HKQuantityTypeIdentifierDietaryRiboflavin' | 'HKQuantityTypeIdentifierDietarySelenium' | 'HKQuantityTypeIdentifierDietarySodium' | 'HKQuantityTypeIdentifierDietarySugar' | 'HKQuantityTypeIdentifierDietaryThiamin' | 'HKQuantityTypeIdentifierDietaryVitaminA' | 'HKQuantityTypeIdentifierDietaryVitaminB12' | 'HKQuantityTypeIdentifierDietaryVitaminB6' | 'HKQuantityTypeIdentifierDietaryVitaminC' | 'HKQuantityTypeIdentifierDietaryVitaminD' | 'HKQuantityTypeIdentifierDietaryVitaminE' | 'HKQuantityTypeIdentifierDietaryVitaminK' | 'HKQuantityTypeIdentifierDietaryWater' | 'HKQuantityTypeIdentifierDietaryZinc' | 'HKQuantityTypeIdentifierDistanceCrossCountrySkiing' | 'HKQuantityTypeIdentifierDistanceCycling' | 'HKQuantityTypeIdentifierDistanceDownhillSnowSports' | 'HKQuantityTypeIdentifierDistancePaddleSports' | 'HKQuantityTypeIdentifierDistanceRowing' | 'HKQuantityTypeIdentifierDistanceSkatingSports' | 'HKQuantityTypeIdentifierDistanceSwimming' | 'HKQuantityTypeIdentifierDistanceWalkingRunning' | 'HKQuantityTypeIdentifierDistanceWheelchair' | 'HKQuantityTypeIdentifierElectrodermalActivity' | 'HKQuantityTypeIdentifierEnvironmentalAudioExposure' | 'HKQuantityTypeIdentifierEnvironmentalSoundReduction' | 'HKQuantityTypeIdentifierEstimatedWorkoutEffortScore' | 'HKQuantityTypeIdentifierFlightsClimbed' | 'HKQuantityTypeIdentifierForcedExpiratoryVolume1' | 'HKQuantityTypeIdentifierForcedVitalCapacity' | 'HKQuantityTypeIdentifierHeadphoneAudioExposure' | 'HKQuantityTypeIdentifierHeartRate' | 'HKQuantityTypeIdentifierHeartRateRecoveryOneMinute' | 'HKQuantityTypeIdentifierHeartRateVariabilitySDNN' | 'HKQuantityTypeIdentifierHeight' | 'HKQuantityTypeIdentifierInhalerUsage' | 'HKQuantityTypeIdentifierInsulinDelivery' | 'HKQuantityTypeIdentifierLeanBodyMass' | 'HKQuantityTypeIdentifierNikeFuel' | 'HKQuantityTypeIdentifierNumberOfAlcoholicBeverages' | 'HKQuantityTypeIdentifierNumberOfTimesFallen' | 'HKQuantityTypeIdentifierOxygenSaturation' | 'HKQuantityTypeIdentifierPaddleSportsSpeed' | 'HKQuantityTypeIdentifierPeakExpiratoryFlowRate' | 'HKQuantityTypeIdentifierPeripheralPerfusionIndex' | 'HKQuantityTypeIdentifierPhysicalEffort' | 'HKQuantityTypeIdentifierPushCount' | 'HKQuantityTypeIdentifierRespiratoryRate' | 'HKQuantityTypeIdentifierRestingHeartRate' | 'HKQuantityTypeIdentifierRowingSpeed' | 'HKQuantityTypeIdentifierRunningGroundContactTime' | 'HKQuantityTypeIdentifierRunningPower' | 'HKQuantityTypeIdentifierRunningSpeed' | 'HKQuantityTypeIdentifierRunningStrideLength' | 'HKQuantityTypeIdentifierRunningVerticalOscillation' | 'HKQuantityTypeIdentifierSixMinuteWalkTestDistance' | 'HKQuantityTypeIdentifierStairAscentSpeed' | 'HKQuantityTypeIdentifierStairDescentSpeed' | 'HKQuantityTypeIdentifierStepCount' | 'HKQuantityTypeIdentifierSwimmingStrokeCount' | 'HKQuantityTypeIdentifierTimeInDaylight' | 'HKQuantityTypeIdentifierUnderwaterDepth' | 'HKQuantityTypeIdentifierUVExposure' | 'HKQuantityTypeIdentifierVO2Max' | 'HKQuantityTypeIdentifierWaistCircumference' | 'HKQuantityTypeIdentifierWalkingAsymmetryPercentage' | 'HKQuantityTypeIdentifierWalkingDoubleSupportPercentage' | 'HKQuantityTypeIdentifierWalkingSpeed' | 'HKQuantityTypeIdentifierWalkingStepLength' | 'HKQuantityTypeIdentifierWaterTemperature' | 'HKQuantityTypeIdentifierWorkoutEffortScore';
5
5
  export type QuantityTypeIdentifier = QuantityTypeIdentifierReadOnly | QuantityTypeIdentifierWriteable;
6
6
  export type CategoryTypeIdentifierReadOnly = 'HKCategoryTypeIdentifierAppleStandHour' | 'HKCategoryTypeIdentifierHeadphoneAudioExposureEvent' | 'HKCategoryTypeIdentifierHighHeartRateEvent' | 'HKCategoryTypeIdentifierHypertensionEvent' | 'HKCategoryTypeIdentifierLowHeartRateEvent';
7
7
  export type CategoryTypeIdentifierWriteable = 'HKCategoryTypeIdentifierAbdominalCramps' | 'HKCategoryTypeIdentifierAcne' | 'HKCategoryTypeIdentifierAppetiteChanges' | 'HKCategoryTypeIdentifierAppleWalkingSteadinessEvent' | 'HKCategoryTypeIdentifierAudioExposureEvent' | 'HKCategoryTypeIdentifierBladderIncontinence' | 'HKCategoryTypeIdentifierBleedingAfterPregnancy' | 'HKCategoryTypeIdentifierBleedingDuringPregnancy' | 'HKCategoryTypeIdentifierBloating' | 'HKCategoryTypeIdentifierBreastPain' | 'HKCategoryTypeIdentifierCervicalMucusQuality' | 'HKCategoryTypeIdentifierChestTightnessOrPain' | 'HKCategoryTypeIdentifierChills' | 'HKCategoryTypeIdentifierConstipation' | 'HKCategoryTypeIdentifierContraceptive' | 'HKCategoryTypeIdentifierCoughing' | 'HKCategoryTypeIdentifierDiarrhea' | 'HKCategoryTypeIdentifierDizziness' | 'HKCategoryTypeIdentifierDrySkin' | 'HKCategoryTypeIdentifierEnvironmentalAudioExposureEvent' | 'HKCategoryTypeIdentifierFainting' | 'HKCategoryTypeIdentifierFatigue' | 'HKCategoryTypeIdentifierFever' | 'HKCategoryTypeIdentifierGeneralizedBodyAche' | 'HKCategoryTypeIdentifierHairLoss' | 'HKCategoryTypeIdentifierHandwashingEvent' | 'HKCategoryTypeIdentifierHeadache' | 'HKCategoryTypeIdentifierHeartburn' | 'HKCategoryTypeIdentifierHotFlashes' | 'HKCategoryTypeIdentifierInfrequentMenstrualCycles' | 'HKCategoryTypeIdentifierIntermenstrualBleeding' | 'HKCategoryTypeIdentifierIrregularHeartRhythmEvent' | 'HKCategoryTypeIdentifierIrregularMenstrualCycles' | 'HKCategoryTypeIdentifierLactation' | 'HKCategoryTypeIdentifierLossOfSmell' | 'HKCategoryTypeIdentifierLossOfTaste' | 'HKCategoryTypeIdentifierLowCardioFitnessEvent' | 'HKCategoryTypeIdentifierLowerBackPain' | 'HKCategoryTypeIdentifierMemoryLapse' | 'HKCategoryTypeIdentifierMenstrualFlow' | 'HKCategoryTypeIdentifierMindfulSession' | 'HKCategoryTypeIdentifierMoodChanges' | 'HKCategoryTypeIdentifierNausea' | 'HKCategoryTypeIdentifierNightSweats' | 'HKCategoryTypeIdentifierOvulationTestResult' | 'HKCategoryTypeIdentifierPelvicPain' | 'HKCategoryTypeIdentifierPersistentIntermenstrualBleeding' | 'HKCategoryTypeIdentifierPregnancy' | 'HKCategoryTypeIdentifierPregnancyTestResult' | 'HKCategoryTypeIdentifierProgesteroneTestResult' | 'HKCategoryTypeIdentifierProlongedMenstrualPeriods' | 'HKCategoryTypeIdentifierRapidPoundingOrFlutteringHeartbeat' | 'HKCategoryTypeIdentifierRunnyNose' | 'HKCategoryTypeIdentifierSexualActivity' | 'HKCategoryTypeIdentifierShortnessOfBreath' | 'HKCategoryTypeIdentifierSinusCongestion' | 'HKCategoryTypeIdentifierSkippedHeartbeat' | 'HKCategoryTypeIdentifierSleepAnalysis' | 'HKCategoryTypeIdentifierSleepApneaEvent' | 'HKCategoryTypeIdentifierSleepChanges' | 'HKCategoryTypeIdentifierSoreThroat' | 'HKCategoryTypeIdentifierToothbrushingEvent' | 'HKCategoryTypeIdentifierVaginalDryness' | 'HKCategoryTypeIdentifierVomiting' | 'HKCategoryTypeIdentifierWheezing';
@@ -19,6 +19,7 @@ export declare const QUANTITY_IDENTIFIER_IOS_AVAILABILITY: {
19
19
  readonly HKQuantityTypeIdentifierBasalEnergyBurned: "8.0";
20
20
  readonly HKQuantityTypeIdentifierBloodAlcoholContent: "8.0";
21
21
  readonly HKQuantityTypeIdentifierBloodGlucose: "8.0";
22
+ readonly HKQuantityTypeIdentifierBloodKetones: "8.0";
22
23
  readonly HKQuantityTypeIdentifierBloodPressureDiastolic: "8.0";
23
24
  readonly HKQuantityTypeIdentifierBloodPressureSystolic: "8.0";
24
25
  readonly HKQuantityTypeIdentifierBodyFatPercentage: "8.0";
@@ -213,6 +214,7 @@ export declare const QUANTITY_IDENTIFIER_CANONICAL_UNITS: {
213
214
  readonly HKQuantityTypeIdentifierBasalEnergyBurned: "kcal";
214
215
  readonly HKQuantityTypeIdentifierBloodAlcoholContent: "%";
215
216
  readonly HKQuantityTypeIdentifierBloodGlucose: "mg/dL";
217
+ readonly HKQuantityTypeIdentifierBloodKetones: "mmol/L";
216
218
  readonly HKQuantityTypeIdentifierBloodPressureDiastolic: "mmHg";
217
219
  readonly HKQuantityTypeIdentifierBloodPressureSystolic: "mmHg";
218
220
  readonly HKQuantityTypeIdentifierBodyFatPercentage: "%";
@@ -894,6 +896,7 @@ export interface QuantityUnitByIdentifierMap {
894
896
  readonly HKQuantityTypeIdentifierBasalEnergyBurned: EnergyUnit;
895
897
  readonly HKQuantityTypeIdentifierBloodAlcoholContent: '%';
896
898
  readonly HKQuantityTypeIdentifierBloodGlucose: BloodGlucoseUnit;
899
+ readonly HKQuantityTypeIdentifierBloodKetones: BloodGlucoseUnit;
897
900
  readonly HKQuantityTypeIdentifierBloodPressureDiastolic: PressureUnit;
898
901
  readonly HKQuantityTypeIdentifierBloodPressureSystolic: PressureUnit;
899
902
  readonly HKQuantityTypeIdentifierBodyFatPercentage: '%';
@@ -87,7 +87,7 @@ export type TemperatureUnit = 'degC' | 'degF' | 'K';
87
87
  */
88
88
  export type UnitOfEnergy = 'kcal' | 'Cal' | 'cal' | 'J';
89
89
  export type EnergyUnit = JouleUnit<MetricPrefix> | UnitOfEnergy;
90
- export type BloodGlucoseUnit = 'mmol<180.15588000005408>/l' | 'mg/dL';
90
+ export type BloodGlucoseUnit = 'mmol<180.15588000005408>/l' | 'mmol/L' | 'mg/dL';
91
91
  export type SpeedUnit<TLength extends LengthUnit, TTime extends TimeUnit> = `${TLength}/${TTime}`;
92
92
  export type CountPerTime<TTime extends TimeUnit> = `count/${TTime}`;
93
93
  export type Unit = BloodGlucoseUnit | CountPerTime<TimeUnit> | EnergyUnit | FrequencyUnit | Units | LengthUnit | MassUnit | PressureUnit | SpeedUnit<LengthUnit, TimeUnit> | TemperatureUnit | TimeUnit | VolumeUnit;
@@ -19,6 +19,7 @@ export interface WorkoutActivity {
19
19
  readonly endDate: Date;
20
20
  readonly uuid: string;
21
21
  readonly duration: number;
22
+ readonly activityType: WorkoutActivityType;
22
23
  }
23
24
  export interface WorkoutRoute {
24
25
  readonly locations: readonly WorkoutRouteLocation[];
@@ -199,6 +199,8 @@ public extension ObjectTypeIdentifier {
199
199
  self = .hkquantitytypeidentifierbloodalcoholcontent
200
200
  case "HKQuantityTypeIdentifierBloodGlucose":
201
201
  self = .hkquantitytypeidentifierbloodglucose
202
+ case "HKQuantityTypeIdentifierBloodKetones":
203
+ self = .hkquantitytypeidentifierbloodketones
202
204
  case "HKQuantityTypeIdentifierBloodPressureDiastolic":
203
205
  self = .hkquantitytypeidentifierbloodpressurediastolic
204
206
  case "HKQuantityTypeIdentifierBloodPressureSystolic":
@@ -619,6 +621,8 @@ public extension ObjectTypeIdentifier {
619
621
  return "HKQuantityTypeIdentifierBloodAlcoholContent"
620
622
  case .hkquantitytypeidentifierbloodglucose:
621
623
  return "HKQuantityTypeIdentifierBloodGlucose"
624
+ case .hkquantitytypeidentifierbloodketones:
625
+ return "HKQuantityTypeIdentifierBloodKetones"
622
626
  case .hkquantitytypeidentifierbloodpressurediastolic:
623
627
  return "HKQuantityTypeIdentifierBloodPressureDiastolic"
624
628
  case .hkquantitytypeidentifierbloodpressuresystolic:
@@ -43,6 +43,8 @@ public extension QuantityTypeIdentifier {
43
43
  self = .hkquantitytypeidentifierbloodalcoholcontent
44
44
  case "HKQuantityTypeIdentifierBloodGlucose":
45
45
  self = .hkquantitytypeidentifierbloodglucose
46
+ case "HKQuantityTypeIdentifierBloodKetones":
47
+ self = .hkquantitytypeidentifierbloodketones
46
48
  case "HKQuantityTypeIdentifierBloodPressureDiastolic":
47
49
  self = .hkquantitytypeidentifierbloodpressurediastolic
48
50
  case "HKQuantityTypeIdentifierBloodPressureSystolic":
@@ -293,6 +295,8 @@ public extension QuantityTypeIdentifier {
293
295
  return "HKQuantityTypeIdentifierBloodAlcoholContent"
294
296
  case .hkquantitytypeidentifierbloodglucose:
295
297
  return "HKQuantityTypeIdentifierBloodGlucose"
298
+ case .hkquantitytypeidentifierbloodketones:
299
+ return "HKQuantityTypeIdentifierBloodKetones"
296
300
  case .hkquantitytypeidentifierbloodpressurediastolic:
297
301
  return "HKQuantityTypeIdentifierBloodPressureDiastolic"
298
302
  case .hkquantitytypeidentifierbloodpressuresystolic:
@@ -33,6 +33,8 @@ public extension QuantityTypeIdentifierWriteable {
33
33
  self = .hkquantitytypeidentifierbloodalcoholcontent
34
34
  case "HKQuantityTypeIdentifierBloodGlucose":
35
35
  self = .hkquantitytypeidentifierbloodglucose
36
+ case "HKQuantityTypeIdentifierBloodKetones":
37
+ self = .hkquantitytypeidentifierbloodketones
36
38
  case "HKQuantityTypeIdentifierBloodPressureDiastolic":
37
39
  self = .hkquantitytypeidentifierbloodpressurediastolic
38
40
  case "HKQuantityTypeIdentifierBloodPressureSystolic":
@@ -273,6 +275,8 @@ public extension QuantityTypeIdentifierWriteable {
273
275
  return "HKQuantityTypeIdentifierBloodAlcoholContent"
274
276
  case .hkquantitytypeidentifierbloodglucose:
275
277
  return "HKQuantityTypeIdentifierBloodGlucose"
278
+ case .hkquantitytypeidentifierbloodketones:
279
+ return "HKQuantityTypeIdentifierBloodKetones"
276
280
  case .hkquantitytypeidentifierbloodpressurediastolic:
277
281
  return "HKQuantityTypeIdentifierBloodPressureDiastolic"
278
282
  case .hkquantitytypeidentifierbloodpressuresystolic:
@@ -187,6 +187,8 @@ public extension SampleTypeIdentifier {
187
187
  self = .hkquantitytypeidentifierbloodalcoholcontent
188
188
  case "HKQuantityTypeIdentifierBloodGlucose":
189
189
  self = .hkquantitytypeidentifierbloodglucose
190
+ case "HKQuantityTypeIdentifierBloodKetones":
191
+ self = .hkquantitytypeidentifierbloodketones
190
192
  case "HKQuantityTypeIdentifierBloodPressureDiastolic":
191
193
  self = .hkquantitytypeidentifierbloodpressurediastolic
192
194
  case "HKQuantityTypeIdentifierBloodPressureSystolic":
@@ -593,6 +595,8 @@ public extension SampleTypeIdentifier {
593
595
  return "HKQuantityTypeIdentifierBloodAlcoholContent"
594
596
  case .hkquantitytypeidentifierbloodglucose:
595
597
  return "HKQuantityTypeIdentifierBloodGlucose"
598
+ case .hkquantitytypeidentifierbloodketones:
599
+ return "HKQuantityTypeIdentifierBloodKetones"
596
600
  case .hkquantitytypeidentifierbloodpressurediastolic:
597
601
  return "HKQuantityTypeIdentifierBloodPressureDiastolic"
598
602
  case .hkquantitytypeidentifierbloodpressuresystolic:
@@ -167,6 +167,8 @@ public extension SampleTypeIdentifierWriteable {
167
167
  self = .hkquantitytypeidentifierbloodalcoholcontent
168
168
  case "HKQuantityTypeIdentifierBloodGlucose":
169
169
  self = .hkquantitytypeidentifierbloodglucose
170
+ case "HKQuantityTypeIdentifierBloodKetones":
171
+ self = .hkquantitytypeidentifierbloodketones
170
172
  case "HKQuantityTypeIdentifierBloodPressureDiastolic":
171
173
  self = .hkquantitytypeidentifierbloodpressurediastolic
172
174
  case "HKQuantityTypeIdentifierBloodPressureSystolic":
@@ -551,6 +553,8 @@ public extension SampleTypeIdentifierWriteable {
551
553
  return "HKQuantityTypeIdentifierBloodAlcoholContent"
552
554
  case .hkquantitytypeidentifierbloodglucose:
553
555
  return "HKQuantityTypeIdentifierBloodGlucose"
556
+ case .hkquantitytypeidentifierbloodketones:
557
+ return "HKQuantityTypeIdentifierBloodKetones"
554
558
  case .hkquantitytypeidentifierbloodpressurediastolic:
555
559
  return "HKQuantityTypeIdentifierBloodPressureDiastolic"
556
560
  case .hkquantitytypeidentifierbloodpressuresystolic: