@kingstinct/react-native-healthkit 11.1.2 → 12.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 (111) hide show
  1. package/README.md +5 -3
  2. package/ios/CoreModule.swift +6 -6
  3. package/ios/Helpers.swift +5 -5
  4. package/ios/QuantityTypeModule.swift +5 -19
  5. package/ios/WorkoutsModule.swift +14 -14
  6. package/lib/commonjs/healthkit.ios.js +11 -6
  7. package/lib/commonjs/healthkit.js +12 -4
  8. package/lib/commonjs/hooks/useHealthkitAuthorization.js +14 -8
  9. package/lib/commonjs/hooks/useSubscribeToQuantitySamples.js +20 -0
  10. package/lib/commonjs/utils/subscribeToQuantitySamples.js +47 -0
  11. package/lib/module/healthkit.ios.js +6 -4
  12. package/lib/module/healthkit.js +11 -3
  13. package/lib/module/hooks/useHealthkitAuthorization.js +14 -8
  14. package/lib/module/hooks/useSubscribeToQuantitySamples.js +17 -0
  15. package/lib/module/utils/subscribeToQuantitySamples.js +43 -0
  16. package/lib/typescript/healthkit.d.ts +19 -9
  17. package/lib/typescript/healthkit.ios.d.ts +27 -18
  18. package/lib/typescript/hooks/useHealthkitAuthorization.d.ts +4 -1
  19. package/lib/typescript/hooks/useSubscribeToQuantitySamples.d.ts +3 -0
  20. package/lib/typescript/specs/CharacteristicTypeModule.nitro.d.ts +2 -2
  21. package/lib/typescript/specs/CoreModule.nitro.d.ts +7 -2
  22. package/lib/typescript/specs/QuantityTypeModule.nitro.d.ts +1 -1
  23. package/lib/typescript/specs/WorkoutProxy.nitro.d.ts +3 -11
  24. package/lib/typescript/specs/WorkoutsModule.nitro.d.ts +1 -1
  25. package/lib/typescript/types/Device.d.ts +8 -8
  26. package/lib/typescript/types/Source.d.ts +2 -2
  27. package/lib/typescript/types/Subscriptions.d.ts +14 -1
  28. package/lib/typescript/types/Workouts.d.ts +1 -1
  29. package/lib/typescript/utils/subscribeToQuantitySamples.d.ts +5 -0
  30. package/nitrogen/generated/ios/ReactNativeHealthkit-Swift-Cxx-Bridge.hpp +94 -55
  31. package/nitrogen/generated/ios/ReactNativeHealthkit-Swift-Cxx-Umbrella.hpp +3 -2
  32. package/nitrogen/generated/ios/c++/HybridCategoryTypeModuleSpecSwift.hpp +3 -2
  33. package/nitrogen/generated/ios/c++/HybridCharacteristicTypeModuleSpecSwift.hpp +3 -0
  34. package/nitrogen/generated/ios/c++/HybridCoreModuleSpecSwift.hpp +10 -4
  35. package/nitrogen/generated/ios/c++/HybridCorrelationTypeModuleSpecSwift.hpp +3 -2
  36. package/nitrogen/generated/ios/c++/HybridElectrocardiogramModuleSpecSwift.hpp +3 -2
  37. package/nitrogen/generated/ios/c++/HybridHeartbeatSeriesModuleSpecSwift.hpp +3 -2
  38. package/nitrogen/generated/ios/c++/HybridQuantityTypeModuleSpecSwift.hpp +4 -3
  39. package/nitrogen/generated/ios/c++/HybridSourceProxySpecSwift.hpp +3 -0
  40. package/nitrogen/generated/ios/c++/HybridStateOfMindModuleSpecSwift.hpp +3 -2
  41. package/nitrogen/generated/ios/c++/HybridWorkoutProxySpecSwift.hpp +7 -22
  42. package/nitrogen/generated/ios/c++/HybridWorkoutsModuleSpecSwift.hpp +5 -4
  43. package/nitrogen/generated/ios/swift/AuthDataTypes.swift +108 -0
  44. package/nitrogen/generated/ios/swift/ECGQueryOptionsWithSortOrder.swift +16 -2
  45. package/nitrogen/generated/ios/swift/HybridCategoryTypeModuleSpec.swift +8 -0
  46. package/nitrogen/generated/ios/swift/HybridCategoryTypeModuleSpec_cxx.swift +10 -1
  47. package/nitrogen/generated/ios/swift/HybridCharacteristicTypeModuleSpec.swift +8 -0
  48. package/nitrogen/generated/ios/swift/HybridCharacteristicTypeModuleSpec_cxx.swift +10 -1
  49. package/nitrogen/generated/ios/swift/HybridCoreModuleSpec.swift +10 -2
  50. package/nitrogen/generated/ios/swift/HybridCoreModuleSpec_cxx.swift +24 -36
  51. package/nitrogen/generated/ios/swift/HybridCorrelationTypeModuleSpec.swift +8 -0
  52. package/nitrogen/generated/ios/swift/HybridCorrelationTypeModuleSpec_cxx.swift +10 -1
  53. package/nitrogen/generated/ios/swift/HybridElectrocardiogramModuleSpec.swift +8 -0
  54. package/nitrogen/generated/ios/swift/HybridElectrocardiogramModuleSpec_cxx.swift +10 -1
  55. package/nitrogen/generated/ios/swift/HybridHeartbeatSeriesModuleSpec.swift +8 -0
  56. package/nitrogen/generated/ios/swift/HybridHeartbeatSeriesModuleSpec_cxx.swift +10 -1
  57. package/nitrogen/generated/ios/swift/HybridQuantityTypeModuleSpec.swift +9 -1
  58. package/nitrogen/generated/ios/swift/HybridQuantityTypeModuleSpec_cxx.swift +13 -12
  59. package/nitrogen/generated/ios/swift/HybridSourceProxySpec.swift +7 -0
  60. package/nitrogen/generated/ios/swift/HybridSourceProxySpec_cxx.swift +9 -1
  61. package/nitrogen/generated/ios/swift/HybridStateOfMindModuleSpec.swift +8 -0
  62. package/nitrogen/generated/ios/swift/HybridStateOfMindModuleSpec_cxx.swift +11 -10
  63. package/nitrogen/generated/ios/swift/HybridWorkoutProxySpec.swift +8 -4
  64. package/nitrogen/generated/ios/swift/HybridWorkoutProxySpec_cxx.swift +10 -53
  65. package/nitrogen/generated/ios/swift/HybridWorkoutsModuleSpec.swift +9 -1
  66. package/nitrogen/generated/ios/swift/HybridWorkoutsModuleSpec_cxx.swift +19 -3
  67. package/nitrogen/generated/ios/swift/PredicateWithMetadataKey.swift +21 -21
  68. package/nitrogen/generated/ios/swift/PredicateWithStartAndEnd.swift +16 -2
  69. package/nitrogen/generated/ios/swift/QueryOptionsWithSortOrder.swift +8 -1
  70. package/nitrogen/generated/ios/swift/QueryOptionsWithSortOrderAndUnit.swift +8 -1
  71. package/nitrogen/generated/ios/swift/StateOfMindSample.swift +29 -21
  72. package/nitrogen/generated/ios/swift/{Variant_String_Double_Bool_Date.swift → Variant_Bool_String_Double_Date.swift} +6 -6
  73. package/nitrogen/generated/ios/swift/WorkoutQueryOptions.swift +8 -1
  74. package/nitrogen/generated/shared/c++/AuthDataTypes.hpp +85 -0
  75. package/nitrogen/generated/shared/c++/CategorySample.hpp +0 -2
  76. package/nitrogen/generated/shared/c++/CategorySampleForSaving.hpp +0 -2
  77. package/nitrogen/generated/shared/c++/CorrelationSample.hpp +0 -2
  78. package/nitrogen/generated/shared/c++/DeletedSample.hpp +1 -2
  79. package/nitrogen/generated/shared/c++/ElectrocardiogramSample.hpp +0 -2
  80. package/nitrogen/generated/shared/c++/HeartbeatSeriesSample.hpp +0 -2
  81. package/nitrogen/generated/shared/c++/HybridCategoryTypeModuleSpec.hpp +0 -2
  82. package/nitrogen/generated/shared/c++/HybridCoreModuleSpec.hpp +5 -5
  83. package/nitrogen/generated/shared/c++/HybridCorrelationTypeModuleSpec.hpp +0 -2
  84. package/nitrogen/generated/shared/c++/HybridQuantityTypeModuleSpec.hpp +1 -3
  85. package/nitrogen/generated/shared/c++/HybridStateOfMindModuleSpec.hpp +0 -2
  86. package/nitrogen/generated/shared/c++/HybridWorkoutProxySpec.cpp +0 -4
  87. package/nitrogen/generated/shared/c++/HybridWorkoutProxySpec.hpp +4 -10
  88. package/nitrogen/generated/shared/c++/HybridWorkoutsModuleSpec.hpp +2 -3
  89. package/nitrogen/generated/shared/c++/PredicateWithMetadataKey.hpp +5 -5
  90. package/nitrogen/generated/shared/c++/QuantitySample.hpp +0 -2
  91. package/nitrogen/generated/shared/c++/QuantitySampleForSaving.hpp +0 -2
  92. package/nitrogen/generated/shared/c++/StateOfMindSample.hpp +0 -2
  93. package/nitrogen/generated/shared/c++/WorkoutSample.hpp +0 -2
  94. package/package.json +7 -7
  95. package/src/healthkit.ios.ts +11 -6
  96. package/src/healthkit.ts +19 -6
  97. package/src/hooks/useHealthkitAuthorization.test.ts +12 -4
  98. package/src/hooks/useHealthkitAuthorization.ts +20 -14
  99. package/src/hooks/useSubscribeToQuantitySamples.ts +31 -0
  100. package/src/specs/CategoryTypeModule.nitro.ts +1 -1
  101. package/src/specs/CharacteristicTypeModule.nitro.ts +2 -2
  102. package/src/specs/CoreModule.nitro.ts +8 -6
  103. package/src/specs/QuantityTypeModule.nitro.ts +1 -1
  104. package/src/specs/WorkoutProxy.nitro.ts +3 -16
  105. package/src/specs/WorkoutsModule.nitro.ts +2 -2
  106. package/src/types/Device.ts +8 -8
  107. package/src/types/InterfaceVerificationExample.ts +2 -2
  108. package/src/types/Source.ts +2 -2
  109. package/src/types/Subscriptions.ts +19 -1
  110. package/src/types/Workouts.ts +1 -1
  111. package/src/utils/subscribeToQuantitySamples.ts +63 -0
package/README.md CHANGED
@@ -84,14 +84,16 @@ Some imperative examples:
84
84
  const isAvailable = await isHealthDataAvailable();
85
85
 
86
86
  /* Read latest sample of any data */
87
- await requestAuthorization(['HKQuantityTypeIdentifierBodyFatPercentage']); // request read permission for bodyFatPercentage
87
+ await requestAuthorization({ toRead: ['HKQuantityTypeIdentifierBodyFatPercentage'] }); // request read permission for bodyFatPercentage
88
88
 
89
89
  const { quantity, unit, startDate, endDate } = await getMostRecentQuantitySample('HKQuantityTypeIdentifierBodyFatPercentage'); // read latest sample
90
90
 
91
91
  console.log(quantity) // 17.5
92
92
  console.log(unit) // %
93
93
 
94
- await requestAuthorization(['HKQuantityTypeIdentifierHeartRate']); // request read permission for heart rate
94
+ await requestAuthorization({
95
+ toRead: ['HKQuantityTypeIdentifierHeartRate']
96
+ }); // request read permission for heart rate
95
97
 
96
98
  /* Subscribe to data (Make sure to request permissions before subscribing to changes) */
97
99
  const [hasRequestedAuthorization, setHasRequestedAuthorization] = useState(false);
@@ -113,7 +115,7 @@ Some imperative examples:
113
115
  }, [hasRequestedAuthorization]);
114
116
 
115
117
  /* write data */
116
- await requestAuthorization([], ['HKQuantityTypeIdentifierInsulinDelivery']); // request write permission for insulin delivery
118
+ await requestAuthorization({ toShare: ['HKQuantityTypeIdentifierInsulinDelivery'] }); // request write permission for insulin delivery
117
119
 
118
120
  saveQuantitySample(
119
121
  'HKQuantityTypeIdentifierInsulinDelivery',
@@ -109,9 +109,9 @@ class CoreModule: HybridCoreModuleSpec {
109
109
  throw RuntimeError.error(withMessage: "[react-native-healthkit] got unrecognized AuthorizationStatus with value \(authStatus.rawValue)")
110
110
  }
111
111
 
112
- func getRequestStatusForAuthorization(toShare: [SampleTypeIdentifierWriteable], toRead: [ObjectTypeIdentifier]) throws -> Promise<AuthorizationRequestStatus> {
113
- let toShare = sampleTypesFromArray(typeIdentifiersWriteable: toShare)
114
- let toRead = objectTypesFromArray(typeIdentifiers: toRead)
112
+ func getRequestStatusForAuthorization(toCheck: AuthDataTypes) throws -> Promise<AuthorizationRequestStatus> {
113
+ let toShare = sampleTypesFromArray(typeIdentifiersWriteable: toCheck.toShare ?? [])
114
+ let toRead = objectTypesFromArray(typeIdentifiers: toCheck.toRead ?? [])
115
115
 
116
116
  return Promise.async {
117
117
  try await withCheckedThrowingContinuation { continuation in
@@ -131,9 +131,9 @@ class CoreModule: HybridCoreModuleSpec {
131
131
  }
132
132
  }
133
133
 
134
- func requestAuthorization(toShare: [SampleTypeIdentifierWriteable], toRead: [ObjectTypeIdentifier]) throws -> Promise<Bool> {
135
- let share = sampleTypesFromArray(typeIdentifiersWriteable: toShare)
136
- let toRead = objectTypesFromArray(typeIdentifiers: toRead)
134
+ func requestAuthorization(toRequest: AuthDataTypes) throws -> Promise<Bool> {
135
+ let share = sampleTypesFromArray(typeIdentifiersWriteable: toRequest.toShare ?? [])
136
+ let toRead = objectTypesFromArray(typeIdentifiers: toRequest.toRead ?? [])
137
137
 
138
138
  return Promise.async {
139
139
  try await withCheckedThrowingContinuation { continuation in
package/ios/Helpers.swift CHANGED
@@ -29,7 +29,7 @@ func getQueryLimit(_ limit: Double?) -> Int {
29
29
  return Int(limit)
30
30
  }
31
31
 
32
- return DEFAULT_QUERY_LIMIT
32
+ return HKObjectQueryNoLimit
33
33
  }
34
34
 
35
35
  func createPredicateForWorkout(filter: PredicateForWorkouts) throws -> NSPredicate {
@@ -144,12 +144,12 @@ func createMetadataPredicate(metadataKey: PredicateWithMetadataKey) throws -> NS
144
144
  let actualValue: Any
145
145
 
146
146
  switch valueVariant {
147
- case .first(let stringValue):
147
+ case .first(let boolValue):
148
+ actualValue = NSNumber(value: boolValue ? 1 : 0)
149
+ case .second(let stringValue):
148
150
  actualValue = stringValue
149
- case .second(let doubleValue):
151
+ case .third(let doubleValue):
150
152
  actualValue = NSNumber(value: doubleValue)
151
- case .third(let boolValue):
152
- actualValue = NSNumber(value: boolValue ? 1 : 0)
153
153
  case .fourth(let dateValue):
154
154
  actualValue = dateValue
155
155
  }
@@ -290,17 +290,11 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
290
290
  }
291
291
  }
292
292
 
293
- func queryStatisticsCollectionForQuantity(identifier: QuantityTypeIdentifier, statistics: [StatisticsOptions], anchorDate: String, intervalComponents: IntervalComponents, options: StatisticsQueryOptions?) throws -> Promise<[QueryStatisticsResponse]> {
293
+ func queryStatisticsCollectionForQuantity(identifier: QuantityTypeIdentifier, statistics: [StatisticsOptions], anchorDate: Date, intervalComponents: IntervalComponents, options: StatisticsQueryOptions?) throws -> Promise<[QueryStatisticsResponse]> {
294
294
  let quantityType = try initializeQuantityType(identifier.stringValue)
295
295
 
296
296
  let predicate = try createPredicate(filter: options?.filter)
297
297
 
298
- // Convert the anchor date string to Date
299
- let dateFormatter = ISO8601DateFormatter()
300
- guard let anchor = dateFormatter.date(from: anchorDate) else {
301
- throw RuntimeError.error(withMessage: "Invalid anchor date format: " + anchorDate)
302
- }
303
-
304
298
  // Create date components from interval
305
299
  var dateComponents = DateComponents()
306
300
  if let minute = intervalComponents.minute {
@@ -324,12 +318,13 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
324
318
 
325
319
  return Promise.async {
326
320
  let unit = try await getUnitToUse(unitOverride: options?.unit, quantityType: quantityType)
321
+
327
322
  return try await withCheckedThrowingContinuation { continuation in
328
323
  let query = HKStatisticsCollectionQuery.init(
329
324
  quantityType: quantityType,
330
325
  quantitySamplePredicate: predicate,
331
326
  options: opts,
332
- anchorDate: anchor,
327
+ anchorDate: anchorDate,
333
328
  intervalComponents: dateComponents
334
329
  )
335
330
 
@@ -413,16 +408,7 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
413
408
  let deletedSamples = deletedSamples?.map { serializeDeletedSample(sample: $0) } ?? []
414
409
  let newAnchor = serializeAnchor(anchor: newAnchor) ?? ""
415
410
 
416
- guard let samples = samples else {
417
- let response = QuantitySamplesWithAnchorResponse(
418
- samples: [],
419
- deletedSamples: deletedSamples,
420
- newAnchor: newAnchor
421
- )
422
- return continuation.resume(returning: response)
423
- }
424
-
425
- let quantitySamples = samples.compactMap { sample in
411
+ let quantitySamples = samples?.compactMap { sample in
426
412
  if let quantitySample = sample as? HKQuantitySample {
427
413
  do {
428
414
  return try serializeQuantitySample(
@@ -437,7 +423,7 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
437
423
  }
438
424
 
439
425
  let response = QuantitySamplesWithAnchorResponse(
440
- samples: quantitySamples,
426
+ samples: quantitySamples ?? [],
441
427
  deletedSamples: deletedSamples,
442
428
  newAnchor: newAnchor,
443
429
  )
@@ -94,20 +94,18 @@ class WorkoutsModule: HybridWorkoutsModuleSpec {
94
94
  quantities: [QuantitySampleForSaving],
95
95
  startDate: Date,
96
96
  endDate: Date,
97
- totals: WorkoutTotals,
98
- metadata: AnyMap
97
+ totals: WorkoutTotals?,
98
+ metadata: AnyMap?
99
99
  ) throws -> Promise<HybridWorkoutProxySpec> {
100
100
 
101
101
  let type = try initializeWorkoutActivityType(UInt(workoutActivityType.rawValue))
102
102
 
103
- // if start and end both exist, ensure that start date is before end date
104
- if let startDate = startDate as Date?, let endDate = endDate as Date? {
105
- if startDate > endDate {
106
- throw RuntimeError.error(withMessage: "endDate must not be less than startDate")
107
- }
103
+ // ensure that start date is before end date
104
+ if startDate > endDate {
105
+ throw RuntimeError.error(withMessage: "endDate must not be less than startDate")
108
106
  }
109
107
 
110
- let metadataDeserialized = anyMapToDictionary(metadata)
108
+ let metadataDeserialized = metadata != nil ? anyMapToDictionary(metadata!) : nil
111
109
 
112
110
  var totalEnergyBurned: HKQuantity?
113
111
  var totalDistance: HKQuantity?
@@ -149,8 +147,8 @@ class WorkoutsModule: HybridWorkoutsModuleSpec {
149
147
  }
150
148
 
151
149
  // if totals are provided override samples
152
- let rawTotalDistance = totals.distance ?? 0.0
153
- let rawTotalEnergy = totals.energyBurned ?? 0.0
150
+ let rawTotalDistance = totals?.distance ?? 0.0
151
+ let rawTotalEnergy = totals?.energyBurned ?? 0.0
154
152
 
155
153
  if rawTotalDistance != 0.0 {
156
154
  totalDistance = HKQuantity(unit: .meter(), doubleValue: rawTotalDistance)
@@ -176,7 +174,7 @@ class WorkoutsModule: HybridWorkoutsModuleSpec {
176
174
  )
177
175
  } else {
178
176
  if #available(iOS 11, *) {
179
- if totalFlightsClimbed != nil {
177
+ if let totalFlightsClimbed = totalFlightsClimbed {
180
178
  workout = HKWorkout.init(
181
179
  activityType: type,
182
180
  start: startDate,
@@ -214,15 +212,17 @@ class WorkoutsModule: HybridWorkoutsModuleSpec {
214
212
  store.save(workout) { (_: Bool, error: Error?) in
215
213
  if let error = error {
216
214
  return continuation.resume(throwing: error)
217
- }
218
- if !initializedSamples.isEmpty {
215
+ } else if !initializedSamples.isEmpty {
219
216
  store.add(initializedSamples, to: workout) { (_, error: Error?) in
220
217
  if let error = error {
221
218
  return continuation.resume(throwing: error)
222
219
  }
220
+ return continuation.resume()
223
221
  }
222
+ } else {
223
+ return continuation.resume()
224
224
  }
225
- return continuation.resume()
225
+
226
226
  }
227
227
  }) as Void
228
228
 
@@ -17,8 +17,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
17
17
  return (mod && mod.__esModule) ? mod : { "default": mod };
18
18
  };
19
19
  Object.defineProperty(exports, "__esModule", { value: true });
20
- exports.saveStateOfMindSample = exports.queryStateOfMindSamples = exports.isProtectedDataAvailable = exports.startWatchApp = exports.subscribeToChanges = exports.saveWorkoutSample = exports.saveQuantitySample = exports.saveCorrelationSample = exports.saveCategorySample = exports.deleteObjects = exports.requestAuthorization = exports.querySources = exports.queryWorkoutSamplesWithAnchor = exports.queryWorkoutSamples = exports.queryStatisticsCollectionForQuantity = exports.queryStatisticsForQuantity = exports.queryQuantitySamplesWithAnchor = exports.queryQuantitySamples = exports.queryElectrocardiogramSamplesWithAnchor = exports.queryElectrocardiogramSamples = exports.queryHeartbeatSeriesSamplesWithAnchor = exports.queryHeartbeatSeriesSamples = exports.queryCorrelationSamples = exports.queryCategorySamplesWithAnchor = exports.queryCategorySamples = exports.isHealthDataAvailableAsync = exports.isHealthDataAvailable = exports.getWheelchairUse = exports.getRequestStatusForAuthorization = exports.getPreferredUnits = exports.getFitzpatrickSkinType = exports.getDateOfBirth = exports.getBloodType = exports.getBiologicalSex = exports.enableBackgroundDelivery = exports.disableBackgroundDelivery = exports.disableAllBackgroundDelivery = exports.authorizationStatusFor = exports.useStatisticsForQuantity = exports.useSources = exports.useIsHealthDataAvailable = exports.useHealthkitAuthorization = exports.useSubscribeToChanges = exports.useMostRecentWorkout = exports.useMostRecentQuantitySample = exports.useMostRecentCategorySample = exports.getPreferredUnit = exports.getMostRecentWorkout = exports.getMostRecentQuantitySample = exports.getMostRecentCategorySample = void 0;
21
- exports.getWheelchairUseAsync = exports.getFitzpatrickSkinTypeAsync = exports.getDateOfBirthAsync = exports.getBloodTypeAsync = exports.getBiologicalSexAsync = exports.areObjectTypesAvailableAsync = exports.areObjectTypesAvailable = exports.isObjectTypeAvailableAsync = exports.isObjectTypeAvailable = exports.unsubscribeQueries = exports.isQuantityCompatibleWithUnit = void 0;
20
+ exports.isProtectedDataAvailable = exports.startWatchApp = exports.saveWorkoutSample = exports.saveQuantitySample = exports.saveCorrelationSample = exports.saveCategorySample = exports.deleteObjects = exports.requestAuthorization = exports.querySources = exports.queryWorkoutSamplesWithAnchor = exports.queryWorkoutSamples = exports.queryStatisticsCollectionForQuantity = exports.queryStatisticsForQuantity = exports.queryQuantitySamplesWithAnchor = exports.queryQuantitySamples = exports.queryElectrocardiogramSamplesWithAnchor = exports.queryElectrocardiogramSamples = exports.queryHeartbeatSeriesSamplesWithAnchor = exports.queryHeartbeatSeriesSamples = exports.queryCorrelationSamples = exports.queryCategorySamplesWithAnchor = exports.queryCategorySamples = exports.isHealthDataAvailableAsync = exports.isHealthDataAvailable = exports.getWheelchairUse = exports.getRequestStatusForAuthorization = exports.getPreferredUnits = exports.getFitzpatrickSkinType = exports.getDateOfBirth = exports.getBloodType = exports.getBiologicalSex = exports.enableBackgroundDelivery = exports.disableBackgroundDelivery = exports.disableAllBackgroundDelivery = exports.authorizationStatusFor = exports.useSubscribeToQuantitySamples = exports.useSubscribeToChanges = exports.useStatisticsForQuantity = exports.useSources = exports.useMostRecentWorkout = exports.useMostRecentQuantitySample = exports.useMostRecentCategorySample = exports.useIsHealthDataAvailable = exports.useHealthkitAuthorization = exports.subscribeToQuantitySamples = exports.subscribeToChanges = exports.getPreferredUnit = exports.getMostRecentWorkout = exports.getMostRecentQuantitySample = exports.getMostRecentCategorySample = void 0;
21
+ exports.getWheelchairUseAsync = exports.getFitzpatrickSkinTypeAsync = exports.getDateOfBirthAsync = exports.getBloodTypeAsync = exports.getBiologicalSexAsync = exports.areObjectTypesAvailableAsync = exports.areObjectTypesAvailable = exports.isObjectTypeAvailableAsync = exports.isObjectTypeAvailable = exports.isQuantityCompatibleWithUnit = exports.saveStateOfMindSample = exports.queryStateOfMindSamples = void 0;
22
22
  const react_native_1 = require("react-native");
23
23
  const useHealthkitAuthorization_1 = __importDefault(require("./hooks/useHealthkitAuthorization"));
24
24
  exports.useHealthkitAuthorization = useHealthkitAuthorization_1.default;
@@ -36,6 +36,8 @@ const useStatisticsForQuantity_1 = __importDefault(require("./hooks/useStatistic
36
36
  exports.useStatisticsForQuantity = useStatisticsForQuantity_1.default;
37
37
  const useSubscribeToChanges_1 = __importDefault(require("./hooks/useSubscribeToChanges"));
38
38
  exports.useSubscribeToChanges = useSubscribeToChanges_1.default;
39
+ const useSubscribeToQuantitySamples_1 = __importDefault(require("./hooks/useSubscribeToQuantitySamples"));
40
+ exports.useSubscribeToQuantitySamples = useSubscribeToQuantitySamples_1.default;
39
41
  const modules_1 = require("./modules");
40
42
  const getMostRecentCategorySample_1 = __importDefault(require("./utils/getMostRecentCategorySample"));
41
43
  exports.getMostRecentCategorySample = getMostRecentCategorySample_1.default;
@@ -45,6 +47,10 @@ const getMostRecentWorkout_1 = __importDefault(require("./utils/getMostRecentWor
45
47
  exports.getMostRecentWorkout = getMostRecentWorkout_1.default;
46
48
  const getPreferredUnit_1 = __importDefault(require("./utils/getPreferredUnit"));
47
49
  exports.getPreferredUnit = getPreferredUnit_1.default;
50
+ const subscribeToChanges_1 = require("./utils/subscribeToChanges");
51
+ Object.defineProperty(exports, "subscribeToChanges", { enumerable: true, get: function () { return subscribeToChanges_1.subscribeToChanges; } });
52
+ const subscribeToQuantitySamples_1 = require("./utils/subscribeToQuantitySamples");
53
+ Object.defineProperty(exports, "subscribeToQuantitySamples", { enumerable: true, get: function () { return subscribeToQuantitySamples_1.subscribeToQuantitySamples; } });
48
54
  __exportStar(require("./types"), exports);
49
55
  const currentMajorVersionIOS = react_native_1.Platform.OS === 'ios' ? Number.parseInt(react_native_1.Platform.Version, 10) : 0;
50
56
  // Named exports - all functions bound to their respective modules
@@ -81,13 +87,11 @@ exports.saveCategorySample = modules_1.CategoryTypes.saveCategorySample.bind(mod
81
87
  exports.saveCorrelationSample = modules_1.CorrelationTypes.saveCorrelationSample.bind(modules_1.CorrelationTypes);
82
88
  exports.saveQuantitySample = modules_1.QuantityTypes.saveQuantitySample.bind(modules_1.QuantityTypes);
83
89
  exports.saveWorkoutSample = modules_1.Workouts.saveWorkoutSample.bind(modules_1.Workouts);
84
- exports.subscribeToChanges = modules_1.Core.subscribeToObserverQuery.bind(modules_1.Core);
85
90
  exports.startWatchApp = modules_1.Workouts.startWatchAppWithWorkoutConfiguration.bind(modules_1.Workouts);
86
91
  exports.isProtectedDataAvailable = modules_1.Core.isProtectedDataAvailable.bind(modules_1.Core);
87
92
  exports.queryStateOfMindSamples = modules_1.StateOfMind.queryStateOfMindSamples.bind(modules_1.StateOfMind);
88
93
  exports.saveStateOfMindSample = modules_1.StateOfMind.saveStateOfMindSample.bind(modules_1.StateOfMind);
89
94
  exports.isQuantityCompatibleWithUnit = modules_1.QuantityTypes.isQuantityCompatibleWithUnit.bind(modules_1.QuantityTypes);
90
- exports.unsubscribeQueries = modules_1.Core.unsubscribeQueries.bind(modules_1.Core);
91
95
  exports.isObjectTypeAvailable = modules_1.Core.isObjectTypeAvailable.bind(modules_1.Core);
92
96
  exports.isObjectTypeAvailableAsync = modules_1.Core.isObjectTypeAvailableAsync.bind(modules_1.Core);
93
97
  exports.areObjectTypesAvailable = modules_1.Core.areObjectTypesAvailable.bind(modules_1.Core);
@@ -145,8 +149,8 @@ exports.default = {
145
149
  saveCorrelationSample: exports.saveCorrelationSample,
146
150
  saveQuantitySample: exports.saveQuantitySample,
147
151
  saveWorkoutSample: exports.saveWorkoutSample,
148
- subscribeToChanges: exports.subscribeToChanges,
149
- unsubscribeQueries: exports.unsubscribeQueries,
152
+ subscribeToChanges: subscribeToChanges_1.subscribeToChanges,
153
+ subscribeToQuantitySamples: subscribeToQuantitySamples_1.subscribeToQuantitySamples,
150
154
  startWatchApp: exports.startWatchApp,
151
155
  isProtectedDataAvailable: exports.isProtectedDataAvailable,
152
156
  queryStateOfMindSamples: exports.queryStateOfMindSamples,
@@ -156,6 +160,7 @@ exports.default = {
156
160
  useMostRecentQuantitySample: useMostRecentQuantitySample_1.default,
157
161
  useMostRecentWorkout: useMostRecentWorkout_1.default,
158
162
  useSubscribeToChanges: useSubscribeToChanges_1.default,
163
+ useSubscribeToQuantitySamples: useSubscribeToQuantitySamples_1.default,
159
164
  useHealthkitAuthorization: useHealthkitAuthorization_1.default,
160
165
  useIsHealthDataAvailable: useIsHealthDataAvailable_1.useIsHealthDataAvailable,
161
166
  useSources: useSources_1.default,
@@ -15,7 +15,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
17
  exports.useSources = exports.useIsHealthDataAvailable = exports.useHealthkitAuthorization = exports.useSubscribeToChanges = exports.useMostRecentWorkout = exports.useMostRecentQuantitySample = exports.getPreferredUnit = exports.getMostRecentWorkout = exports.getMostRecentQuantitySample = exports.saveStateOfMindSample = exports.queryStateOfMindSamples = exports.startWatchApp = exports.saveWorkoutSample = exports.queryWorkoutSamplesWithAnchor = exports.queryWorkoutSamples = exports.queryElectrocardiogramSamplesWithAnchor = exports.queryElectrocardiogramSamples = exports.queryHeartbeatSeriesSamplesWithAnchor = exports.queryHeartbeatSeriesSamples = exports.saveCorrelationSample = exports.queryCorrelationSamples = exports.saveCategorySample = exports.isQuantityCompatibleWithUnit = exports.saveQuantitySample = exports.queryStatisticsCollectionForQuantity = exports.queryStatisticsForQuantity = exports.queryQuantitySamplesWithAnchor = exports.queryQuantitySamples = exports.getWheelchairUse = exports.getFitzpatrickSkinType = exports.getDateOfBirth = exports.getBloodType = exports.getBiologicalSex = exports.areObjectTypesAvailableAsync = exports.areObjectTypesAvailable = exports.isObjectTypeAvailableAsync = exports.isObjectTypeAvailable = exports.isProtectedDataAvailable = exports.subscribeToChanges = exports.deleteObjects = exports.requestAuthorization = exports.querySources = exports.isHealthDataAvailableAsync = exports.isHealthDataAvailable = exports.getRequestStatusForAuthorization = exports.getPreferredUnits = exports.enableBackgroundDelivery = exports.disableBackgroundDelivery = exports.disableAllBackgroundDelivery = exports.authorizationStatusFor = void 0;
18
- exports.unsubscribeQueries = exports.getWheelchairUseAsync = exports.getFitzpatrickSkinTypeAsync = exports.getDateOfBirthAsync = exports.getBloodTypeAsync = exports.getBiologicalSexAsync = exports.useStatisticsForQuantity = void 0;
18
+ exports.useSubscribeToQuantitySamples = exports.subscribeToQuantitySamples = exports.getWheelchairUseAsync = exports.getFitzpatrickSkinTypeAsync = exports.getDateOfBirthAsync = exports.getBloodTypeAsync = exports.getBiologicalSexAsync = exports.useStatisticsForQuantity = void 0;
19
19
  exports.queryCategorySamples = queryCategorySamples;
20
20
  exports.queryCategorySamplesWithAnchor = queryCategorySamplesWithAnchor;
21
21
  exports.getMostRecentCategorySample = getMostRecentCategorySample;
@@ -49,7 +49,9 @@ exports.isHealthDataAvailableAsync = UnavailableFnFromModule('isHealthDataAvaila
49
49
  exports.querySources = UnavailableFnFromModule('querySources', Promise.resolve([]));
50
50
  exports.requestAuthorization = UnavailableFnFromModule('requestAuthorization', Promise.resolve(false));
51
51
  exports.deleteObjects = UnavailableFnFromModule('deleteObjects', Promise.resolve(0));
52
- exports.subscribeToChanges = UnavailableFnFromModule('subscribeToChanges', 'dummy-query-uuid'); // Mocking the observer query UUID
52
+ exports.subscribeToChanges = UnavailableFnFromModule('subscribeToChanges', {
53
+ remove: () => false,
54
+ }); // Mocking the observer query UUID
53
55
  exports.isProtectedDataAvailable = UnavailableFnFromModule('isProtectedDataAvailable', false);
54
56
  exports.isObjectTypeAvailable = UnavailableFnFromModule('isObjectTypeAvailable', false);
55
57
  exports.isObjectTypeAvailableAsync = UnavailableFnFromModule('isObjectTypeAvailableAsync', Promise.resolve(false));
@@ -160,14 +162,18 @@ exports.getBloodTypeAsync = UnavailableFnFromModule('getBloodTypeAsync', Promise
160
162
  exports.getDateOfBirthAsync = UnavailableFnFromModule('getDateOfBirthAsync', Promise.resolve(new Date(0))); // Assuming string for date
161
163
  exports.getFitzpatrickSkinTypeAsync = UnavailableFnFromModule('getFitzpatrickSkinTypeAsync', Promise.resolve(Characteristics_1.FitzpatrickSkinType.notSet));
162
164
  exports.getWheelchairUseAsync = UnavailableFnFromModule('getWheelchairUseAsync', Promise.resolve(Characteristics_1.WheelchairUse.notSet));
163
- exports.unsubscribeQueries = UnavailableFnFromModule('unsubscribeQueries', 0);
165
+ const subscribeToQuantitySamples = UnavailableFnFromModule('subscribeToQuantitySamples', {
166
+ remove: () => false,
167
+ }); // Mocking the observer query UUID
168
+ exports.subscribeToQuantitySamples = subscribeToQuantitySamples;
169
+ const useSubscribeToQuantitySamples = UnavailableFnFromModule('useSubscribeToQuantitySamples', undefined); // Mocking callback structure
170
+ exports.useSubscribeToQuantitySamples = useSubscribeToQuantitySamples;
164
171
  // --- Default Export ---
165
172
  // This attempts to match the structure of the default export from index.ios.ts
166
173
  const HealthkitModule = {
167
174
  // All named exports are also part of the default export object
168
175
  authorizationStatusFor: exports.authorizationStatusFor,
169
176
  isObjectTypeAvailable: exports.isObjectTypeAvailable,
170
- unsubscribeQueries: exports.unsubscribeQueries,
171
177
  isObjectTypeAvailableAsync: exports.isObjectTypeAvailableAsync,
172
178
  areObjectTypesAvailable: exports.areObjectTypesAvailable,
173
179
  areObjectTypesAvailableAsync: exports.areObjectTypesAvailableAsync,
@@ -213,6 +219,8 @@ const HealthkitModule = {
213
219
  isProtectedDataAvailable: exports.isProtectedDataAvailable,
214
220
  queryStateOfMindSamples: exports.queryStateOfMindSamples,
215
221
  saveStateOfMindSample: exports.saveStateOfMindSample,
222
+ subscribeToQuantitySamples,
223
+ useSubscribeToQuantitySamples,
216
224
  // Hooks
217
225
  useMostRecentCategorySample,
218
226
  useMostRecentQuantitySample: exports.useMostRecentQuantitySample,
@@ -8,21 +8,27 @@ const modules_1 = require("../modules");
8
8
  * @see {@link https://developer.apple.com/documentation/healthkit/hkhealthstore/1614152-requestauthorization Apple Docs - requestAuthorization}
9
9
  * @see {@link https://developer.apple.com/documentation/healthkit/authorizing_access_to_health_data Apple Docs - Authorizing access to health data}
10
10
  */
11
- const useHealthkitAuthorization = (read, write) => {
11
+ const useHealthkitAuthorization = ({ toWrite, toRead, }) => {
12
12
  const [status, setStatus] = (0, react_1.useState)(null);
13
- const readMemo = (0, react_1.useRef)(read);
14
- const writeMemo = (0, react_1.useRef)(write);
13
+ const readMemo = (0, react_1.useRef)(toRead);
14
+ const writeMemo = (0, react_1.useRef)(toWrite);
15
15
  (0, react_1.useEffect)(() => {
16
- readMemo.current = read;
17
- writeMemo.current = write;
18
- }, [read, write]);
16
+ readMemo.current = toRead;
17
+ writeMemo.current = toWrite;
18
+ }, [toRead, toWrite]);
19
19
  const refreshAuthStatus = (0, react_1.useCallback)(async () => {
20
- const auth = await modules_1.Core.getRequestStatusForAuthorization(writeMemo.current ?? [], readMemo.current);
20
+ const auth = await modules_1.Core.getRequestStatusForAuthorization({
21
+ toShare: writeMemo.current,
22
+ toRead: readMemo.current,
23
+ });
21
24
  setStatus(auth);
22
25
  return auth;
23
26
  }, []);
24
27
  const request = (0, react_1.useCallback)(async () => {
25
- await modules_1.Core.requestAuthorization(writeMemo.current ?? [], readMemo.current);
28
+ await modules_1.Core.requestAuthorization({
29
+ toShare: writeMemo.current,
30
+ toRead: readMemo.current,
31
+ });
26
32
  return refreshAuthStatus();
27
33
  }, [refreshAuthStatus]);
28
34
  (0, react_1.useEffect)(() => {
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.useSubscribeToQuantitySamples = useSubscribeToQuantitySamples;
4
+ const react_1 = require("react");
5
+ const subscribeToQuantitySamples_1 = require("../utils/subscribeToQuantitySamples");
6
+ function useSubscribeToQuantitySamples(identifier, onChange) {
7
+ const onChangeRef = (0, react_1.useRef)(onChange);
8
+ (0, react_1.useEffect)(() => {
9
+ onChangeRef.current = onChange;
10
+ }, [onChange]);
11
+ (0, react_1.useEffect)(() => {
12
+ const subscription = (0, subscribeToQuantitySamples_1.subscribeToQuantitySamples)(identifier, (args) => {
13
+ onChangeRef.current(args);
14
+ });
15
+ return () => {
16
+ subscription.remove();
17
+ };
18
+ }, [identifier]);
19
+ }
20
+ exports.default = useSubscribeToQuantitySamples;
@@ -0,0 +1,47 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.subscribeToQuantitySamples = void 0;
4
+ const modules_1 = require("../modules");
5
+ const subscribeToChanges_1 = require("./subscribeToChanges");
6
+ const subscribeToQuantitySamples = (identifier, callback, after) => {
7
+ let anchor;
8
+ const afterDate = after ?? new Date();
9
+ const init = async () => {
10
+ // we need to do an initial query to get a handle for the deletedSamples
11
+ const { newAnchor } = await modules_1.QuantityTypes.queryQuantitySamplesWithAnchor(identifier, {
12
+ filter: {
13
+ startDate: afterDate,
14
+ },
15
+ });
16
+ anchor = newAnchor;
17
+ };
18
+ init();
19
+ return (0, subscribeToChanges_1.subscribeToChanges)(identifier, async ({ errorMessage }) => {
20
+ if (errorMessage) {
21
+ return callback({
22
+ typeIdentifier: identifier,
23
+ errorMessage,
24
+ });
25
+ }
26
+ // seems like all deletedSamples are included when no anchor is provided, so we don't want to return those for the first query
27
+ const hadAnchorWhenDoingQuery = !!anchor;
28
+ const { samples, newAnchor, deletedSamples } = await modules_1.QuantityTypes.queryQuantitySamplesWithAnchor(identifier, {
29
+ anchor,
30
+ filter: {
31
+ startDate: afterDate,
32
+ },
33
+ });
34
+ anchor = newAnchor;
35
+ const hasNewSamples = samples.length > 0 ||
36
+ (deletedSamples.length > 0 && hadAnchorWhenDoingQuery);
37
+ if (hasNewSamples) {
38
+ callback({
39
+ typeIdentifier: identifier,
40
+ samples,
41
+ anchor: newAnchor,
42
+ deletedSamples: hadAnchorWhenDoingQuery ? deletedSamples : [],
43
+ });
44
+ }
45
+ });
46
+ };
47
+ exports.subscribeToQuantitySamples = subscribeToQuantitySamples;
@@ -7,14 +7,17 @@ import useMostRecentWorkout from './hooks/useMostRecentWorkout';
7
7
  import useSources from './hooks/useSources';
8
8
  import useStatisticsForQuantity from './hooks/useStatisticsForQuantity';
9
9
  import useSubscribeToChanges from './hooks/useSubscribeToChanges';
10
+ import useSubscribeToQuantitySamples from './hooks/useSubscribeToQuantitySamples';
10
11
  import { CategoryTypes, Characteristics, Core, CorrelationTypes, Electrocardiograms, HeartbeatSeries, QuantityTypes, StateOfMind, Workouts, } from './modules';
11
12
  import getMostRecentCategorySample from './utils/getMostRecentCategorySample';
12
13
  import getMostRecentQuantitySample from './utils/getMostRecentQuantitySample';
13
14
  import getMostRecentWorkout from './utils/getMostRecentWorkout';
14
15
  import getPreferredUnit from './utils/getPreferredUnit';
16
+ import { subscribeToChanges } from './utils/subscribeToChanges';
17
+ import { subscribeToQuantitySamples } from './utils/subscribeToQuantitySamples';
15
18
  export * from './types';
16
19
  const currentMajorVersionIOS = Platform.OS === 'ios' ? Number.parseInt(Platform.Version, 10) : 0;
17
- export { getMostRecentCategorySample, getMostRecentQuantitySample, getMostRecentWorkout, getPreferredUnit, useMostRecentCategorySample, useMostRecentQuantitySample, useMostRecentWorkout, useSubscribeToChanges, useHealthkitAuthorization, useIsHealthDataAvailable, useSources, useStatisticsForQuantity, };
20
+ export { getMostRecentCategorySample, getMostRecentQuantitySample, getMostRecentWorkout, getPreferredUnit, subscribeToChanges, subscribeToQuantitySamples, useHealthkitAuthorization, useIsHealthDataAvailable, useMostRecentCategorySample, useMostRecentQuantitySample, useMostRecentWorkout, useSources, useStatisticsForQuantity, useSubscribeToChanges, useSubscribeToQuantitySamples, };
18
21
  // Named exports - all functions bound to their respective modules
19
22
  export const authorizationStatusFor = Core.authorizationStatusFor.bind(Core);
20
23
  export const disableAllBackgroundDelivery = Core.disableAllBackgroundDelivery.bind(Core);
@@ -49,13 +52,11 @@ export const saveCategorySample = CategoryTypes.saveCategorySample.bind(Category
49
52
  export const saveCorrelationSample = CorrelationTypes.saveCorrelationSample.bind(CorrelationTypes);
50
53
  export const saveQuantitySample = QuantityTypes.saveQuantitySample.bind(QuantityTypes);
51
54
  export const saveWorkoutSample = Workouts.saveWorkoutSample.bind(Workouts);
52
- export const subscribeToChanges = Core.subscribeToObserverQuery.bind(Core);
53
55
  export const startWatchApp = Workouts.startWatchAppWithWorkoutConfiguration.bind(Workouts);
54
56
  export const isProtectedDataAvailable = Core.isProtectedDataAvailable.bind(Core);
55
57
  export const queryStateOfMindSamples = StateOfMind.queryStateOfMindSamples.bind(StateOfMind);
56
58
  export const saveStateOfMindSample = StateOfMind.saveStateOfMindSample.bind(StateOfMind);
57
59
  export const isQuantityCompatibleWithUnit = QuantityTypes.isQuantityCompatibleWithUnit.bind(QuantityTypes);
58
- export const unsubscribeQueries = Core.unsubscribeQueries.bind(Core);
59
60
  export const isObjectTypeAvailable = Core.isObjectTypeAvailable.bind(Core);
60
61
  export const isObjectTypeAvailableAsync = Core.isObjectTypeAvailableAsync.bind(Core);
61
62
  export const areObjectTypesAvailable = Core.areObjectTypesAvailable.bind(Core);
@@ -114,7 +115,7 @@ export default {
114
115
  saveQuantitySample,
115
116
  saveWorkoutSample,
116
117
  subscribeToChanges,
117
- unsubscribeQueries,
118
+ subscribeToQuantitySamples,
118
119
  startWatchApp,
119
120
  isProtectedDataAvailable,
120
121
  queryStateOfMindSamples,
@@ -124,6 +125,7 @@ export default {
124
125
  useMostRecentQuantitySample,
125
126
  useMostRecentWorkout,
126
127
  useSubscribeToChanges,
128
+ useSubscribeToQuantitySamples,
127
129
  useHealthkitAuthorization,
128
130
  useIsHealthDataAvailable,
129
131
  useSources,
@@ -27,7 +27,9 @@ export const isHealthDataAvailableAsync = UnavailableFnFromModule('isHealthDataA
27
27
  export const querySources = UnavailableFnFromModule('querySources', Promise.resolve([]));
28
28
  export const requestAuthorization = UnavailableFnFromModule('requestAuthorization', Promise.resolve(false));
29
29
  export const deleteObjects = UnavailableFnFromModule('deleteObjects', Promise.resolve(0));
30
- export const subscribeToChanges = UnavailableFnFromModule('subscribeToChanges', 'dummy-query-uuid'); // Mocking the observer query UUID
30
+ export const subscribeToChanges = UnavailableFnFromModule('subscribeToChanges', {
31
+ remove: () => false,
32
+ }); // Mocking the observer query UUID
31
33
  export const isProtectedDataAvailable = UnavailableFnFromModule('isProtectedDataAvailable', false);
32
34
  export const isObjectTypeAvailable = UnavailableFnFromModule('isObjectTypeAvailable', false);
33
35
  export const isObjectTypeAvailableAsync = UnavailableFnFromModule('isObjectTypeAvailableAsync', Promise.resolve(false));
@@ -138,14 +140,18 @@ export const getBloodTypeAsync = UnavailableFnFromModule('getBloodTypeAsync', Pr
138
140
  export const getDateOfBirthAsync = UnavailableFnFromModule('getDateOfBirthAsync', Promise.resolve(new Date(0))); // Assuming string for date
139
141
  export const getFitzpatrickSkinTypeAsync = UnavailableFnFromModule('getFitzpatrickSkinTypeAsync', Promise.resolve(FitzpatrickSkinType.notSet));
140
142
  export const getWheelchairUseAsync = UnavailableFnFromModule('getWheelchairUseAsync', Promise.resolve(WheelchairUse.notSet));
141
- export const unsubscribeQueries = UnavailableFnFromModule('unsubscribeQueries', 0);
143
+ const subscribeToQuantitySamples = UnavailableFnFromModule('subscribeToQuantitySamples', {
144
+ remove: () => false,
145
+ }); // Mocking the observer query UUID
146
+ export { subscribeToQuantitySamples };
147
+ const useSubscribeToQuantitySamples = UnavailableFnFromModule('useSubscribeToQuantitySamples', undefined); // Mocking callback structure
148
+ export { useSubscribeToQuantitySamples };
142
149
  // --- Default Export ---
143
150
  // This attempts to match the structure of the default export from index.ios.ts
144
151
  const HealthkitModule = {
145
152
  // All named exports are also part of the default export object
146
153
  authorizationStatusFor,
147
154
  isObjectTypeAvailable,
148
- unsubscribeQueries,
149
155
  isObjectTypeAvailableAsync,
150
156
  areObjectTypesAvailable,
151
157
  areObjectTypesAvailableAsync,
@@ -191,6 +197,8 @@ const HealthkitModule = {
191
197
  isProtectedDataAvailable,
192
198
  queryStateOfMindSamples,
193
199
  saveStateOfMindSample,
200
+ subscribeToQuantitySamples,
201
+ useSubscribeToQuantitySamples,
194
202
  // Hooks
195
203
  useMostRecentCategorySample,
196
204
  useMostRecentQuantitySample,
@@ -5,21 +5,27 @@ import { Core } from '../modules';
5
5
  * @see {@link https://developer.apple.com/documentation/healthkit/hkhealthstore/1614152-requestauthorization Apple Docs - requestAuthorization}
6
6
  * @see {@link https://developer.apple.com/documentation/healthkit/authorizing_access_to_health_data Apple Docs - Authorizing access to health data}
7
7
  */
8
- export const useHealthkitAuthorization = (read, write) => {
8
+ export const useHealthkitAuthorization = ({ toWrite, toRead, }) => {
9
9
  const [status, setStatus] = useState(null);
10
- const readMemo = useRef(read);
11
- const writeMemo = useRef(write);
10
+ const readMemo = useRef(toRead);
11
+ const writeMemo = useRef(toWrite);
12
12
  useEffect(() => {
13
- readMemo.current = read;
14
- writeMemo.current = write;
15
- }, [read, write]);
13
+ readMemo.current = toRead;
14
+ writeMemo.current = toWrite;
15
+ }, [toRead, toWrite]);
16
16
  const refreshAuthStatus = useCallback(async () => {
17
- const auth = await Core.getRequestStatusForAuthorization(writeMemo.current ?? [], readMemo.current);
17
+ const auth = await Core.getRequestStatusForAuthorization({
18
+ toShare: writeMemo.current,
19
+ toRead: readMemo.current,
20
+ });
18
21
  setStatus(auth);
19
22
  return auth;
20
23
  }, []);
21
24
  const request = useCallback(async () => {
22
- await Core.requestAuthorization(writeMemo.current ?? [], readMemo.current);
25
+ await Core.requestAuthorization({
26
+ toShare: writeMemo.current,
27
+ toRead: readMemo.current,
28
+ });
23
29
  return refreshAuthStatus();
24
30
  }, [refreshAuthStatus]);
25
31
  useEffect(() => {
@@ -0,0 +1,17 @@
1
+ import { useEffect, useRef } from 'react';
2
+ import { subscribeToQuantitySamples } from '../utils/subscribeToQuantitySamples';
3
+ export function useSubscribeToQuantitySamples(identifier, onChange) {
4
+ const onChangeRef = useRef(onChange);
5
+ useEffect(() => {
6
+ onChangeRef.current = onChange;
7
+ }, [onChange]);
8
+ useEffect(() => {
9
+ const subscription = subscribeToQuantitySamples(identifier, (args) => {
10
+ onChangeRef.current(args);
11
+ });
12
+ return () => {
13
+ subscription.remove();
14
+ };
15
+ }, [identifier]);
16
+ }
17
+ export default useSubscribeToQuantitySamples;
@@ -0,0 +1,43 @@
1
+ import { QuantityTypes } from '../modules';
2
+ import { subscribeToChanges } from './subscribeToChanges';
3
+ export const subscribeToQuantitySamples = (identifier, callback, after) => {
4
+ let anchor;
5
+ const afterDate = after ?? new Date();
6
+ const init = async () => {
7
+ // we need to do an initial query to get a handle for the deletedSamples
8
+ const { newAnchor } = await QuantityTypes.queryQuantitySamplesWithAnchor(identifier, {
9
+ filter: {
10
+ startDate: afterDate,
11
+ },
12
+ });
13
+ anchor = newAnchor;
14
+ };
15
+ init();
16
+ return subscribeToChanges(identifier, async ({ errorMessage }) => {
17
+ if (errorMessage) {
18
+ return callback({
19
+ typeIdentifier: identifier,
20
+ errorMessage,
21
+ });
22
+ }
23
+ // seems like all deletedSamples are included when no anchor is provided, so we don't want to return those for the first query
24
+ const hadAnchorWhenDoingQuery = !!anchor;
25
+ const { samples, newAnchor, deletedSamples } = await QuantityTypes.queryQuantitySamplesWithAnchor(identifier, {
26
+ anchor,
27
+ filter: {
28
+ startDate: afterDate,
29
+ },
30
+ });
31
+ anchor = newAnchor;
32
+ const hasNewSamples = samples.length > 0 ||
33
+ (deletedSamples.length > 0 && hadAnchorWhenDoingQuery);
34
+ if (hasNewSamples) {
35
+ callback({
36
+ typeIdentifier: identifier,
37
+ samples,
38
+ anchor: newAnchor,
39
+ deletedSamples: hadAnchorWhenDoingQuery ? deletedSamples : [],
40
+ });
41
+ }
42
+ });
43
+ };