@kingstinct/react-native-healthkit 12.2.0 → 13.0.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 (68) hide show
  1. package/ios/CategoryTypeModule.swift +6 -4
  2. package/ios/CorrelationTypeModule.swift +11 -5
  3. package/ios/Helpers.swift +7 -0
  4. package/ios/PredicateHelpers.swift +1 -1
  5. package/ios/QuantityTypeModule.swift +244 -100
  6. package/ios/StateOfMindModule.swift +4 -2
  7. package/lib/commonjs/healthkit.ios.js +6 -2
  8. package/lib/commonjs/healthkit.js +13 -7
  9. package/lib/module/healthkit.ios.js +4 -0
  10. package/lib/module/healthkit.js +11 -5
  11. package/lib/typescript/healthkit.d.ts +6 -4
  12. package/lib/typescript/healthkit.ios.d.ts +12 -8
  13. package/lib/typescript/specs/CategoryTypeModule.nitro.d.ts +2 -2
  14. package/lib/typescript/specs/CorrelationTypeModule.nitro.d.ts +1 -1
  15. package/lib/typescript/specs/QuantityTypeModule.nitro.d.ts +4 -2
  16. package/lib/typescript/specs/StateOfMindModule.nitro.d.ts +1 -1
  17. package/lib/typescript/types/QuantitySample.d.ts +1 -1
  18. package/lib/typescript/types/QuantityType.d.ts +6 -1
  19. package/nitrogen/generated/ios/ReactNativeHealthkit-Swift-Cxx-Bridge.cpp +56 -16
  20. package/nitrogen/generated/ios/ReactNativeHealthkit-Swift-Cxx-Bridge.hpp +406 -117
  21. package/nitrogen/generated/ios/ReactNativeHealthkit-Swift-Cxx-Umbrella.hpp +3 -0
  22. package/nitrogen/generated/ios/c++/HybridCategoryTypeModuleSpecSwift.hpp +8 -8
  23. package/nitrogen/generated/ios/c++/HybridCorrelationTypeModuleSpecSwift.hpp +28 -28
  24. package/nitrogen/generated/ios/c++/HybridQuantityTypeModuleSpecSwift.hpp +25 -6
  25. package/nitrogen/generated/ios/c++/HybridStateOfMindModuleSpecSwift.hpp +1 -1
  26. package/nitrogen/generated/ios/c++/HybridWorkoutsModuleSpecSwift.hpp +1 -1
  27. package/nitrogen/generated/ios/swift/FilterForWorkouts.swift +53 -53
  28. package/nitrogen/generated/ios/swift/FilterForWorkoutsBase.swift +53 -53
  29. package/nitrogen/generated/ios/swift/Func_void_std__optional_CategorySample_.swift +47 -0
  30. package/nitrogen/generated/ios/swift/Func_void_std__optional_CorrelationSample_.swift +47 -0
  31. package/nitrogen/generated/ios/swift/Func_void_std__optional_QuantitySample_.swift +47 -0
  32. package/nitrogen/generated/ios/swift/Func_void_std__optional_StateOfMindSample_.swift +47 -0
  33. package/nitrogen/generated/ios/swift/Func_void_std__vector_QueryStatisticsResponseFromSingleSource_.swift +47 -0
  34. package/nitrogen/generated/ios/swift/HybridCategoryTypeModuleSpec.swift +1 -1
  35. package/nitrogen/generated/ios/swift/HybridCategoryTypeModuleSpec_cxx.swift +21 -8
  36. package/nitrogen/generated/ios/swift/HybridCorrelationTypeModuleSpec.swift +1 -1
  37. package/nitrogen/generated/ios/swift/HybridCorrelationTypeModuleSpec_cxx.swift +21 -8
  38. package/nitrogen/generated/ios/swift/HybridQuantityTypeModuleSpec.swift +3 -1
  39. package/nitrogen/generated/ios/swift/HybridQuantityTypeModuleSpec_cxx.swift +71 -8
  40. package/nitrogen/generated/ios/swift/HybridStateOfMindModuleSpec.swift +1 -1
  41. package/nitrogen/generated/ios/swift/HybridStateOfMindModuleSpec_cxx.swift +13 -7
  42. package/nitrogen/generated/ios/swift/QuantitySampleForSaving.swift +24 -5
  43. package/nitrogen/generated/ios/swift/QueryStatisticsResponse.swift +34 -1
  44. package/nitrogen/generated/ios/swift/QueryStatisticsResponseFromSingleSource.swift +266 -0
  45. package/nitrogen/generated/ios/swift/StatisticsOptions.swift +0 -4
  46. package/nitrogen/generated/shared/c++/FilterForWorkouts.hpp +10 -10
  47. package/nitrogen/generated/shared/c++/FilterForWorkoutsBase.hpp +11 -11
  48. package/nitrogen/generated/shared/c++/HybridCategoryTypeModuleSpec.hpp +5 -4
  49. package/nitrogen/generated/shared/c++/HybridCorrelationTypeModuleSpec.hpp +5 -4
  50. package/nitrogen/generated/shared/c++/HybridQuantityTypeModuleSpec.cpp +2 -0
  51. package/nitrogen/generated/shared/c++/HybridQuantityTypeModuleSpec.hpp +8 -3
  52. package/nitrogen/generated/shared/c++/HybridStateOfMindModuleSpec.hpp +2 -2
  53. package/nitrogen/generated/shared/c++/QuantitySampleForSaving.hpp +6 -6
  54. package/nitrogen/generated/shared/c++/QueryStatisticsResponse.hpp +11 -2
  55. package/nitrogen/generated/shared/c++/QueryStatisticsResponseFromSingleSource.hpp +121 -0
  56. package/nitrogen/generated/shared/c++/StatisticsOptions.hpp +0 -4
  57. package/package.json +1 -1
  58. package/src/healthkit.ios.ts +8 -0
  59. package/src/healthkit.ts +20 -5
  60. package/src/hooks/queryStatisticsForQuantity.test.ts +4 -1
  61. package/src/specs/CategoryTypeModule.nitro.ts +4 -4
  62. package/src/specs/CorrelationTypeModule.nitro.ts +2 -2
  63. package/src/specs/MedicationModule.nitro.ts +2 -7
  64. package/src/specs/QuantityTypeModule.nitro.ts +17 -2
  65. package/src/specs/StateOfMindModule.nitro.ts +1 -1
  66. package/src/types/QuantitySample.ts +1 -1
  67. package/src/types/QuantityType.ts +8 -1
  68. package/src/types/Subscriptions.ts +1 -1
@@ -7,8 +7,8 @@ class CategoryTypeModule: HybridCategoryTypeModuleSpec {
7
7
  value: Double,
8
8
  startDate: Date,
9
9
  endDate: Date,
10
- metadata: AnyMap
11
- ) -> Promise<Bool> {
10
+ metadata: AnyMap?
11
+ ) -> Promise<CategorySample?> {
12
12
  return Promise.async {
13
13
  let type = try initializeCategoryType(identifier.stringValue)
14
14
 
@@ -17,10 +17,12 @@ class CategoryTypeModule: HybridCategoryTypeModuleSpec {
17
17
  value: Int(value),
18
18
  start: startDate,
19
19
  end: endDate,
20
- metadata: anyMapToDictionary(metadata)
20
+ metadata: anyMapToDictionaryOptional(metadata)
21
21
  )
22
22
 
23
- return try await saveAsync(sample: sample)
23
+ let succeeded = try await saveAsync(sample: sample)
24
+
25
+ return succeeded ? serializeCategorySample(sample: sample) : nil
24
26
  }
25
27
  }
26
28
 
@@ -121,8 +121,8 @@ class CorrelationTypeModule: HybridCorrelationTypeModuleSpec {
121
121
  samples: [SampleForSaving],
122
122
  start: Date,
123
123
  end: Date,
124
- metadata: AnyMap
125
- ) -> Promise<Bool> {
124
+ metadata: AnyMap?
125
+ ) -> Promise<CorrelationSample?> {
126
126
  return Promise.async {
127
127
  let correlationType = try initializeCorrelationType(typeIdentifier.stringValue)
128
128
 
@@ -144,7 +144,7 @@ class CorrelationTypeModule: HybridCorrelationTypeModuleSpec {
144
144
  quantity: quantity,
145
145
  start: start,
146
146
  end: end,
147
- metadata: anyMapToDictionary(quantitySample.metadata)
147
+ metadata: anyMapToDictionaryOptional(quantitySample.metadata)
148
148
  )
149
149
  initializedSamples.insert(hkQuantitySample)
150
150
 
@@ -171,10 +171,16 @@ class CorrelationTypeModule: HybridCorrelationTypeModuleSpec {
171
171
  start: start,
172
172
  end: end,
173
173
  objects: initializedSamples,
174
- metadata: anyMapToDictionary(metadata)
174
+ metadata: anyMapToDictionaryOptional(metadata)
175
175
  )
176
176
 
177
- return try await saveAsync(sample: correlation)
177
+ let succeeded = try await saveAsync(sample: correlation)
178
+
179
+ let unitMap = try await getUnitMap(correlations: [correlation])
180
+
181
+ return succeeded
182
+ ? serializeCorrelationSample(correlation: correlation, unitMap: unitMap)
183
+ : nil
178
184
  }
179
185
  }
180
186
 
package/ios/Helpers.swift CHANGED
@@ -421,6 +421,13 @@ func parseWorkoutConfiguration(_ config: WorkoutConfiguration) -> HKWorkoutConfi
421
421
  return configuration
422
422
  }
423
423
 
424
+ func anyMapToDictionaryOptional(_ anyMap: AnyMap?) -> [String: Any]? {
425
+ if let anyMap = anyMap {
426
+ return anyMapToDictionary(anyMap)
427
+ }
428
+ return nil
429
+ }
430
+
424
431
  func anyMapToDictionary(_ anyMap: AnyMap) -> [String: Any] {
425
432
  var dict = [String: Any]()
426
433
  anyMap.getAllKeys().forEach { key in
@@ -71,11 +71,11 @@ func getPredicateForWorkoutBase(_ filter: FilterForWorkouts?) -> FilterForWorkou
71
71
  return FilterForWorkoutsBase(
72
72
  workoutActivityType: filter.workoutActivityType,
73
73
  duration: filter.duration,
74
+ sources: filter.sources,
74
75
  uuid: filter.uuid,
75
76
  uuids: filter.uuids,
76
77
  metadata: filter.metadata,
77
78
  date: filter.date,
78
- sources: filter.sources
79
79
  )
80
80
  }
81
81
  return nil
@@ -10,6 +10,39 @@ func emptyStatisticsResponse(from: Date, to: Date) -> QueryStatisticsResponse {
10
10
  return response
11
11
  }
12
12
 
13
+ func queryStatisticsForQuantityInternal(
14
+ quantityType: HKQuantityType,
15
+ statistics: [StatisticsOptions],
16
+ options: StatisticsQueryOptions?
17
+ ) async throws -> HKStatistics {
18
+ let predicate = createPredicateForSamples(options?.filter)
19
+
20
+ return try await withCheckedThrowingContinuation { continuation in
21
+ let query = HKStatisticsQuery.init(
22
+ quantityType: quantityType,
23
+ quantitySamplePredicate: predicate,
24
+ options: buildStatisticsOptions(statistics: statistics)
25
+ ) { (_, stats: HKStatistics?, error: Error?) in
26
+ DispatchQueue.main.async {
27
+ if let error = error {
28
+ return continuation.resume(throwing: error)
29
+ }
30
+
31
+ if let stats = stats {
32
+ return continuation.resume(returning: stats)
33
+ } else {
34
+ return continuation.resume(
35
+ throwing: runtimeErrorWithPrefix(
36
+ "queryStatisticsForQuantityInternal: unexpected empty response"))
37
+ }
38
+
39
+ }
40
+ }
41
+
42
+ store.execute(query)
43
+ }
44
+ }
45
+
13
46
  func serializeStatistics(gottenStats: HKStatistics, unit: HKUnit) -> QueryStatisticsResponse {
14
47
  var response = QueryStatisticsResponse()
15
48
 
@@ -70,6 +103,128 @@ func serializeStatistics(gottenStats: HKStatistics, unit: HKUnit) -> QueryStatis
70
103
  return response
71
104
  }
72
105
 
106
+ func queryStatisticsCollectionForQuantityInternal(
107
+ quantityType: HKQuantityType,
108
+ statistics: [StatisticsOptions],
109
+ anchorDate: Date,
110
+ intervalComponents: IntervalComponents,
111
+ options: StatisticsQueryOptions?
112
+ ) async throws -> HKStatisticsCollection {
113
+ let predicate = createPredicateForSamples(options?.filter)
114
+
115
+ // Create date components from interval
116
+ var dateComponents = DateComponents()
117
+ if let minute = intervalComponents.minute {
118
+ dateComponents.minute = Int(minute)
119
+ }
120
+ if let hour = intervalComponents.hour {
121
+ dateComponents.hour = Int(hour)
122
+ }
123
+ if let day = intervalComponents.day {
124
+ dateComponents.day = Int(day)
125
+ }
126
+ if let month = intervalComponents.month {
127
+ dateComponents.month = Int(month)
128
+ }
129
+ if let year = intervalComponents.year {
130
+ dateComponents.year = Int(year)
131
+ }
132
+
133
+ // Build statistics options
134
+ let opts = buildStatisticsOptions(statistics: statistics)
135
+
136
+ let unit = try await getUnitToUse(unitOverride: options?.unit, quantityType: quantityType)
137
+
138
+ return try await withCheckedThrowingContinuation { continuation in
139
+ let query = HKStatisticsCollectionQuery.init(
140
+ quantityType: quantityType,
141
+ quantitySamplePredicate: predicate,
142
+ options: opts,
143
+ anchorDate: anchorDate,
144
+ intervalComponents: dateComponents
145
+ )
146
+
147
+ query.initialResultsHandler = { (_, results: HKStatisticsCollection?, error: Error?) in
148
+ if let error = error {
149
+ return continuation.resume(throwing: error)
150
+ }
151
+
152
+ guard let statistics = results else {
153
+ return continuation.resume(throwing: runtimeErrorWithPrefix("queryStatisticsCollectionForQuantityInternal: unexpected empty results"))
154
+ }
155
+
156
+ return continuation.resume(returning: statistics)
157
+ }
158
+
159
+ store.execute(query)
160
+ }
161
+ }
162
+
163
+ func serializeStatisticsPerSource(gottenStats: HKStatistics, unit: HKUnit)
164
+ -> [QueryStatisticsResponseFromSingleSource] {
165
+ if let sources = gottenStats.sources {
166
+ return sources.map { source in
167
+ var response = QueryStatisticsResponseFromSingleSource()
168
+
169
+ response.startDate = gottenStats.startDate
170
+ response.endDate = gottenStats.endDate
171
+
172
+ if let averageQuantity = gottenStats.averageQuantity(for: source) {
173
+ response.averageQuantity = Quantity(
174
+ unit: unit.unitString,
175
+ quantity: averageQuantity.doubleValue(for: unit)
176
+ )
177
+ }
178
+ if let maximumQuantity = gottenStats.maximumQuantity(for: source) {
179
+ response.maximumQuantity = Quantity(
180
+ unit: unit.unitString,
181
+ quantity: maximumQuantity.doubleValue(for: unit)
182
+ )
183
+ }
184
+ if let minimumQuantity = gottenStats.minimumQuantity(for: source) {
185
+ response.minimumQuantity = Quantity(
186
+ unit: unit.unitString,
187
+ quantity: minimumQuantity.doubleValue(for: unit)
188
+ )
189
+ }
190
+ if let sumQuantity = gottenStats.sumQuantity(for: source) {
191
+ response.sumQuantity = Quantity(
192
+ unit: unit.unitString,
193
+ quantity: sumQuantity.doubleValue(for: unit)
194
+ )
195
+ }
196
+
197
+ if #available(iOS 12, *) {
198
+ if let mostRecent = gottenStats.mostRecentQuantity(for: source) {
199
+ response.mostRecentQuantity = Quantity(
200
+ unit: unit.unitString,
201
+ quantity: mostRecent.doubleValue(for: unit)
202
+ )
203
+ }
204
+
205
+ if let mostRecentDateInterval = gottenStats.mostRecentQuantityDateInterval(for: source) {
206
+ response.mostRecentQuantityDateInterval = QuantityDateInterval(
207
+ from: mostRecentDateInterval.start,
208
+ to: mostRecentDateInterval.end
209
+ )
210
+ }
211
+ }
212
+
213
+ if #available(iOS 13, *) {
214
+ if let duration = gottenStats.duration(for: source) {
215
+ let durationUnit = HKUnit.second()
216
+ response.duration = Quantity(
217
+ unit: durationUnit.unitString,
218
+ quantity: duration.doubleValue(for: durationUnit)
219
+ )
220
+ }
221
+ }
222
+ return response
223
+ }
224
+ }
225
+ return []
226
+ }
227
+
73
228
  func getAnyMapValue(_ anyMap: AnyMap, key: String) -> Any? {
74
229
  if anyMap.isBool(key: key) {
75
230
  return anyMap.getBoolean(key: key)
@@ -116,9 +271,6 @@ func buildStatisticsOptions(statistics: [StatisticsOptions]) -> HKStatisticsOpti
116
271
  opts.insert(HKStatisticsOptions.mostRecent)
117
272
  }
118
273
  }
119
- if statistic == .separatebysource {
120
- opts.insert(HKStatisticsOptions.separateBySource)
121
- }
122
274
  }
123
275
  return opts
124
276
  }
@@ -144,6 +296,56 @@ func handleHKNoDataOrThrow<T>(
144
296
  }
145
297
 
146
298
  class QuantityTypeModule: HybridQuantityTypeModuleSpec {
299
+ func queryStatisticsForQuantitySeparateBySource(
300
+ identifier: QuantityTypeIdentifier, statistics: [StatisticsOptions],
301
+ options: StatisticsQueryOptions?
302
+ ) -> Promise<[QueryStatisticsResponseFromSingleSource]> {
303
+ return Promise.async {
304
+ let quantityType = try initializeQuantityType(identifier.stringValue)
305
+
306
+ let gottenStats = try await queryStatisticsForQuantityInternal(
307
+ quantityType: quantityType,
308
+ statistics: statistics,
309
+ options: options
310
+ )
311
+
312
+ let unit = try await getUnitToUse(
313
+ unitOverride: options?.unit,
314
+ quantityType: quantityType
315
+ )
316
+
317
+ let response = serializeStatisticsPerSource(gottenStats: gottenStats, unit: unit)
318
+
319
+ return response
320
+ }
321
+ }
322
+
323
+ func queryStatisticsCollectionForQuantitySeparateBySource(
324
+ identifier: QuantityTypeIdentifier, statistics: [StatisticsOptions], anchorDate: Date,
325
+ intervalComponents: IntervalComponents, options: StatisticsQueryOptions?
326
+ ) -> Promise<[QueryStatisticsResponseFromSingleSource]> {
327
+ return Promise.async {
328
+ let quantityType = try initializeQuantityType(identifier.stringValue)
329
+
330
+ let statistics = try await queryStatisticsCollectionForQuantityInternal(
331
+ quantityType: quantityType,
332
+ statistics: statistics,
333
+ anchorDate: anchorDate,
334
+ intervalComponents: intervalComponents,
335
+ options: options
336
+ )
337
+
338
+ let unit = try await getUnitToUse(
339
+ unitOverride: options?.unit,
340
+ quantityType: quantityType
341
+ )
342
+
343
+ return statistics.statistics().flatMap { statistics in
344
+ return serializeStatisticsPerSource(gottenStats: statistics, unit: unit)
345
+ }
346
+ }
347
+ }
348
+
147
349
  func aggregationStyle(identifier: QuantityTypeIdentifier) throws -> AggregationStyle {
148
350
  let sampleType = try initializeQuantityType(identifier.stringValue)
149
351
 
@@ -168,34 +370,21 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
168
370
  ) -> Promise<QueryStatisticsResponse> {
169
371
  return Promise.async {
170
372
  let quantityType = try initializeQuantityType(identifier.stringValue)
171
- let predicate = createPredicateForSamples(options?.filter)
172
- let unit = try await getUnitToUse(unitOverride: options?.unit, quantityType: quantityType)
173
- return try await withCheckedThrowingContinuation { continuation in
174
- let query = HKStatisticsQuery.init(
175
- quantityType: quantityType,
176
- quantitySamplePredicate: predicate,
177
- options: buildStatisticsOptions(statistics: statistics)
178
- ) { (_, stats: HKStatistics?, error: Error?) in
179
- DispatchQueue.main.async {
180
- if let error = error {
181
- return handleHKNoDataOrThrow(error: error, continuation: continuation) {
182
- QueryStatisticsResponse()
183
- }
184
- }
185
-
186
- guard let gottenStats = stats else {
187
- let emptyResponse = QueryStatisticsResponse()
188
- return continuation.resume(returning: emptyResponse)
189
- }
190
-
191
- let response = serializeStatistics(gottenStats: gottenStats, unit: unit)
192
-
193
- continuation.resume(returning: response)
194
- }
195
- }
196
373
 
197
- store.execute(query)
198
- }
374
+ let gottenStats = try await queryStatisticsForQuantityInternal(
375
+ quantityType: quantityType,
376
+ statistics: statistics,
377
+ options: options
378
+ )
379
+
380
+ let unit = try await getUnitToUse(
381
+ unitOverride: options?.unit,
382
+ quantityType: quantityType
383
+ )
384
+
385
+ let response = serializeStatistics(gottenStats: gottenStats, unit: unit)
386
+
387
+ return response
199
388
  }
200
389
  }
201
390
 
@@ -206,73 +395,21 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
206
395
  return Promise.async {
207
396
  let quantityType = try initializeQuantityType(identifier.stringValue)
208
397
 
209
- let predicate = createPredicateForSamples(options?.filter)
210
-
211
- // Create date components from interval
212
- var dateComponents = DateComponents()
213
- if let minute = intervalComponents.minute {
214
- dateComponents.minute = Int(minute)
215
- }
216
- if let hour = intervalComponents.hour {
217
- dateComponents.hour = Int(hour)
218
- }
219
- if let day = intervalComponents.day {
220
- dateComponents.day = Int(day)
221
- }
222
- if let month = intervalComponents.month {
223
- dateComponents.month = Int(month)
224
- }
225
- if let year = intervalComponents.year {
226
- dateComponents.year = Int(year)
227
- }
228
-
229
- // Build statistics options
230
- let opts = buildStatisticsOptions(statistics: statistics)
231
-
232
- let unit = try await getUnitToUse(unitOverride: options?.unit, quantityType: quantityType)
233
-
234
- return try await withCheckedThrowingContinuation { continuation in
235
- let query = HKStatisticsCollectionQuery.init(
236
- quantityType: quantityType,
237
- quantitySamplePredicate: predicate,
238
- options: opts,
239
- anchorDate: anchorDate,
240
- intervalComponents: dateComponents
241
- )
242
-
243
- query.initialResultsHandler = { (_, results: HKStatisticsCollection?, error: Error?) in
244
- if let error = error {
245
- return handleHKNoDataOrThrow(error: error, continuation: continuation) {
246
- []
247
- }
248
- }
249
-
250
- guard let statistics = results else {
251
- continuation.resume(returning: [])
252
- return
253
- }
254
-
255
- var responseArray: [QueryStatisticsResponse] = []
256
-
257
- // Limit enumeration to the range in the provided filter if possible
258
- var enumerateFrom = Date.distantPast
259
- var enumerateTo = Date()
260
-
261
- if let filter = options?.filter {
262
- enumerateFrom = filter.date?.startDate ?? enumerateFrom
263
- enumerateTo = filter.date?.endDate ?? enumerateTo
264
- }
265
-
266
- statistics.enumerateStatistics(from: enumerateFrom, to: enumerateTo) { stats, _ in
267
- let response = serializeStatistics(gottenStats: stats, unit: unit)
268
-
269
- responseArray.append(response)
270
- }
398
+ let statistics = try await queryStatisticsCollectionForQuantityInternal(
399
+ quantityType: quantityType,
400
+ statistics: statistics,
401
+ anchorDate: anchorDate,
402
+ intervalComponents: intervalComponents,
403
+ options: options
404
+ )
271
405
 
272
- continuation.resume(returning: responseArray)
273
- }
406
+ let unit = try await getUnitToUse(
407
+ unitOverride: options?.unit,
408
+ quantityType: quantityType
409
+ )
274
410
 
275
- store.execute(query)
411
+ return statistics.statistics().map { statistics in
412
+ return serializeStatistics(gottenStats: statistics, unit: unit)
276
413
  }
277
414
  }
278
415
  }
@@ -319,16 +456,20 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
319
456
  }
320
457
 
321
458
  func saveQuantitySample(
322
- identifier: QuantityTypeIdentifier, unit: String, value: Double, start: Date, end: Date,
323
- metadata: AnyMap
324
- ) -> Promise<Bool> {
459
+ identifier: QuantityTypeIdentifier,
460
+ unit: String,
461
+ value: Double,
462
+ start: Date,
463
+ end: Date,
464
+ metadata: AnyMap?
465
+ ) -> Promise<QuantitySample?> {
325
466
  return Promise.async {
326
467
  let unit = HKUnit.init(from: unit)
327
468
  let quantity = HKQuantity.init(unit: unit, doubleValue: value)
328
469
  let typeIdentifier = HKQuantityType(
329
470
  HKQuantityTypeIdentifier(rawValue: identifier.stringValue)
330
471
  )
331
- let metadata = anyMapToDictionary(metadata)
472
+ let metadata = anyMapToDictionaryOptional(metadata)
332
473
 
333
474
  let sample = HKQuantitySample.init(
334
475
  type: typeIdentifier,
@@ -337,7 +478,10 @@ class QuantityTypeModule: HybridQuantityTypeModuleSpec {
337
478
  end: end,
338
479
  metadata: metadata
339
480
  )
340
- return try await saveAsync(sample: sample)
481
+
482
+ let succeeded = try await saveAsync(sample: sample)
483
+
484
+ return succeeded ? try serializeQuantitySample(sample: sample, unit: unit) : nil
341
485
  }
342
486
  }
343
487
 
@@ -145,7 +145,7 @@ import NitroModules
145
145
  labels: [StateOfMindLabel],
146
146
  associations: [StateOfMindAssociation],
147
147
  metadata: AnyMap?
148
- ) -> Promise<Bool> {
148
+ ) -> Promise<StateOfMindSample?> {
149
149
 
150
150
  return Promise.async {
151
151
  if #available(iOS 18, *) {
@@ -179,7 +179,9 @@ import NitroModules
179
179
  metadata: anyMapToDictionary(metadata ?? AnyMap())
180
180
  )
181
181
 
182
- return try await saveAsync(sample: sample)
182
+ let succeeded = try await saveAsync(sample: sample)
183
+
184
+ return succeeded ? serializeStateOfMindSample(sample: sample) : nil
183
185
  }
184
186
  throw runtimeErrorWithPrefix(
185
187
  "saveStateOfMindSample: Unknown StateOfMindKind rawValue: \(kind.rawValue)")
@@ -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.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.queryCorrelationSamplesWithAnchor = 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.useSubscribeToCategorySamples = exports.useStatisticsForQuantity = exports.useSources = exports.useMostRecentWorkout = exports.useMostRecentQuantitySample = exports.useMostRecentCategorySample = exports.useIsHealthDataAvailable = exports.useHealthkitAuthorization = exports.subscribeToQuantitySamples = exports.subscribeToChanges = exports.subscribeToCategorySamples = exports.getPreferredUnit = exports.getMostRecentWorkout = exports.getMostRecentQuantitySample = exports.getMostRecentCategorySample = void 0;
21
- exports.getWheelchairUseAsync = exports.getFitzpatrickSkinTypeAsync = exports.getDateOfBirthAsync = exports.getBloodTypeAsync = exports.getBiologicalSexAsync = exports.currentAppSource = exports.queryMedicationEventsWithAnchor = exports.queryMedicationEvents = exports.queryMedications = exports.requestMedicationsAuthorization = exports.areObjectTypesAvailableAsync = exports.areObjectTypesAvailable = exports.isObjectTypeAvailableAsync = exports.isObjectTypeAvailable = exports.isQuantityCompatibleWithUnit = exports.saveStateOfMindSample = exports.queryStateOfMindSamplesWithAnchor = exports.queryStateOfMindSamples = exports.isProtectedDataAvailable = exports.startWatchApp = exports.saveWorkoutSample = void 0;
20
+ exports.saveCategorySample = exports.deleteObjects = exports.requestAuthorization = exports.querySources = exports.queryWorkoutSamplesWithAnchor = exports.queryWorkoutSamples = exports.queryStatisticsCollectionForQuantitySeparateBySource = exports.queryStatisticsForQuantitySeparateBySource = exports.queryStatisticsCollectionForQuantity = exports.queryStatisticsForQuantity = exports.queryQuantitySamplesWithAnchor = exports.queryQuantitySamples = exports.queryElectrocardiogramSamplesWithAnchor = exports.queryElectrocardiogramSamples = exports.queryHeartbeatSeriesSamplesWithAnchor = exports.queryHeartbeatSeriesSamples = exports.queryCorrelationSamplesWithAnchor = 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.useSubscribeToCategorySamples = exports.useStatisticsForQuantity = exports.useSources = exports.useMostRecentWorkout = exports.useMostRecentQuantitySample = exports.useMostRecentCategorySample = exports.useIsHealthDataAvailable = exports.useHealthkitAuthorization = exports.subscribeToQuantitySamples = exports.subscribeToChanges = exports.subscribeToCategorySamples = exports.getPreferredUnit = exports.getMostRecentWorkout = exports.getMostRecentQuantitySample = exports.getMostRecentCategorySample = void 0;
21
+ exports.getWheelchairUseAsync = exports.getFitzpatrickSkinTypeAsync = exports.getDateOfBirthAsync = exports.getBloodTypeAsync = exports.getBiologicalSexAsync = exports.currentAppSource = exports.queryMedicationEventsWithAnchor = exports.queryMedicationEvents = exports.queryMedications = exports.requestMedicationsAuthorization = exports.areObjectTypesAvailableAsync = exports.areObjectTypesAvailable = exports.isObjectTypeAvailableAsync = exports.isObjectTypeAvailable = exports.isQuantityCompatibleWithUnit = exports.saveStateOfMindSample = exports.queryStateOfMindSamplesWithAnchor = exports.queryStateOfMindSamples = exports.isProtectedDataAvailable = exports.startWatchApp = exports.saveWorkoutSample = exports.saveQuantitySample = exports.saveCorrelationSample = 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;
@@ -83,6 +83,8 @@ exports.queryQuantitySamples = modules_1.QuantityTypes.queryQuantitySamples.bind
83
83
  exports.queryQuantitySamplesWithAnchor = modules_1.QuantityTypes.queryQuantitySamplesWithAnchor.bind(modules_1.QuantityTypes);
84
84
  exports.queryStatisticsForQuantity = modules_1.QuantityTypes.queryStatisticsForQuantity.bind(modules_1.QuantityTypes);
85
85
  exports.queryStatisticsCollectionForQuantity = modules_1.QuantityTypes.queryStatisticsCollectionForQuantity.bind(modules_1.QuantityTypes);
86
+ exports.queryStatisticsForQuantitySeparateBySource = modules_1.QuantityTypes.queryStatisticsForQuantitySeparateBySource.bind(modules_1.QuantityTypes);
87
+ exports.queryStatisticsCollectionForQuantitySeparateBySource = modules_1.QuantityTypes.queryStatisticsCollectionForQuantitySeparateBySource.bind(modules_1.QuantityTypes);
86
88
  exports.queryWorkoutSamples = modules_1.Workouts.queryWorkoutSamples.bind(modules_1.Workouts);
87
89
  exports.queryWorkoutSamplesWithAnchor = modules_1.Workouts.queryWorkoutSamplesWithAnchor.bind(modules_1.Workouts);
88
90
  exports.querySources = modules_1.Core.querySources.bind(modules_1.Core);
@@ -152,6 +154,8 @@ exports.default = {
152
154
  queryQuantitySamplesWithAnchor: exports.queryQuantitySamplesWithAnchor,
153
155
  queryStatisticsForQuantity: exports.queryStatisticsForQuantity,
154
156
  queryStatisticsCollectionForQuantity: exports.queryStatisticsCollectionForQuantity,
157
+ queryStatisticsForQuantitySeparateBySource: exports.queryStatisticsForQuantitySeparateBySource,
158
+ queryStatisticsCollectionForQuantitySeparateBySource: exports.queryStatisticsCollectionForQuantitySeparateBySource,
155
159
  queryWorkoutSamples: exports.queryWorkoutSamples,
156
160
  queryWorkoutSamplesWithAnchor: exports.queryWorkoutSamplesWithAnchor,
157
161
  querySources: exports.querySources,
@@ -14,8 +14,8 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.useHealthkitAuthorization = exports.useSubscribeToChanges = exports.useMostRecentWorkout = exports.useMostRecentQuantitySample = exports.getPreferredUnit = exports.getMostRecentWorkout = exports.getMostRecentQuantitySample = exports.saveStateOfMindSample = exports.queryCorrelationSamplesWithAnchor = exports.queryStateOfMindSamplesWithAnchor = 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.requestMedicationsAuthorization = exports.subscribeToCategorySamples = exports.useSubscribeToCategorySamples = exports.useSubscribeToQuantitySamples = exports.queryMedicationEventsWithAnchor = exports.queryMedicationEvents = exports.queryMedications = exports.currentAppSource = exports.subscribeToQuantitySamples = exports.getWheelchairUseAsync = exports.getFitzpatrickSkinTypeAsync = exports.getDateOfBirthAsync = exports.getBloodTypeAsync = exports.getBiologicalSexAsync = exports.useStatisticsForQuantity = exports.useSources = exports.useIsHealthDataAvailable = void 0;
17
+ exports.useMostRecentWorkout = exports.useMostRecentQuantitySample = exports.getPreferredUnit = exports.getMostRecentWorkout = exports.getMostRecentQuantitySample = exports.saveStateOfMindSample = exports.queryCorrelationSamplesWithAnchor = exports.queryStateOfMindSamplesWithAnchor = 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.queryStatisticsCollectionForQuantitySeparateBySource = exports.queryStatisticsForQuantitySeparateBySource = 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.requestMedicationsAuthorization = exports.subscribeToCategorySamples = exports.useSubscribeToCategorySamples = exports.useSubscribeToQuantitySamples = exports.queryMedicationEventsWithAnchor = exports.queryMedicationEvents = exports.queryMedications = exports.currentAppSource = exports.subscribeToQuantitySamples = exports.getWheelchairUseAsync = exports.getFitzpatrickSkinTypeAsync = exports.getDateOfBirthAsync = exports.getBloodTypeAsync = exports.getBiologicalSexAsync = exports.useStatisticsForQuantity = exports.useSources = exports.useIsHealthDataAvailable = exports.useHealthkitAuthorization = exports.useSubscribeToChanges = void 0;
19
19
  exports.queryCategorySamples = queryCategorySamples;
20
20
  exports.queryCategorySamplesWithAnchor = queryCategorySamplesWithAnchor;
21
21
  exports.getMostRecentCategorySample = getMostRecentCategorySample;
@@ -70,9 +70,13 @@ exports.queryQuantitySamplesWithAnchor = UnavailableFnFromModule('queryQuantityS
70
70
  deletedSamples: [],
71
71
  newAnchor: '',
72
72
  }));
73
- exports.queryStatisticsForQuantity = UnavailableFnFromModule('queryStatisticsForQuantity', Promise.resolve({}));
73
+ exports.queryStatisticsForQuantity = UnavailableFnFromModule('queryStatisticsForQuantity', Promise.resolve({
74
+ sources: [],
75
+ }));
74
76
  exports.queryStatisticsCollectionForQuantity = UnavailableFnFromModule('queryStatisticsCollectionForQuantity', Promise.resolve([]));
75
- exports.saveQuantitySample = UnavailableFnFromModule('saveQuantitySample', Promise.resolve(false));
77
+ exports.queryStatisticsForQuantitySeparateBySource = UnavailableFnFromModule('queryStatisticsForQuantitySeparateBySource', Promise.resolve([]));
78
+ exports.queryStatisticsCollectionForQuantitySeparateBySource = UnavailableFnFromModule('queryStatisticsCollectionForQuantitySeparateBySource', Promise.resolve([]));
79
+ exports.saveQuantitySample = UnavailableFnFromModule('saveQuantitySample', Promise.resolve(undefined));
76
80
  exports.isQuantityCompatibleWithUnit = UnavailableFnFromModule('isQuantityCompatibleWithUnit', false);
77
81
  // CategoryTypeModule functions
78
82
  function queryCategorySamples(_categoryTypeIdentifier, _options) {
@@ -93,10 +97,10 @@ function queryCategorySamplesWithAnchor(_categoryTypeIdentifier, _options) {
93
97
  newAnchor: '',
94
98
  });
95
99
  }
96
- exports.saveCategorySample = UnavailableFnFromModule('saveCategorySample', Promise.resolve(false));
100
+ exports.saveCategorySample = UnavailableFnFromModule('saveCategorySample', Promise.resolve(undefined));
97
101
  // CorrelationTypeModule functions
98
102
  exports.queryCorrelationSamples = UnavailableFnFromModule('queryCorrelationSamples', Promise.resolve([]));
99
- exports.saveCorrelationSample = UnavailableFnFromModule('saveCorrelationSample', Promise.resolve(false));
103
+ exports.saveCorrelationSample = UnavailableFnFromModule('saveCorrelationSample', Promise.resolve(undefined));
100
104
  // HeartbeatSeriesModule functions
101
105
  exports.queryHeartbeatSeriesSamples = UnavailableFnFromModule('queryHeartbeatSeriesSamples', Promise.resolve([]));
102
106
  exports.queryHeartbeatSeriesSamplesWithAnchor = UnavailableFnFromModule('queryHeartbeatSeriesSamplesWithAnchor', Promise.resolve({
@@ -133,7 +137,7 @@ exports.queryCorrelationSamplesWithAnchor = UnavailableFnFromModule('queryCorrel
133
137
  deletedSamples: [],
134
138
  newAnchor: '',
135
139
  }));
136
- exports.saveStateOfMindSample = UnavailableFnFromModule('saveStateOfMindSample', Promise.resolve(false));
140
+ exports.saveStateOfMindSample = UnavailableFnFromModule('saveStateOfMindSample', Promise.resolve(undefined));
137
141
  // Utility functions (from original export list)
138
142
  function getMostRecentCategorySample(_identifier) {
139
143
  if (react_native_1.Platform.OS !== 'ios' && !hasWarned) {
@@ -226,6 +230,8 @@ const HealthkitModule = {
226
230
  queryQuantitySamplesWithAnchor: exports.queryQuantitySamplesWithAnchor,
227
231
  queryStatisticsForQuantity: exports.queryStatisticsForQuantity,
228
232
  queryStatisticsCollectionForQuantity: exports.queryStatisticsCollectionForQuantity,
233
+ queryStatisticsForQuantitySeparateBySource: exports.queryStatisticsForQuantitySeparateBySource,
234
+ queryStatisticsCollectionForQuantitySeparateBySource: exports.queryStatisticsCollectionForQuantitySeparateBySource,
229
235
  queryWorkoutSamples: exports.queryWorkoutSamples,
230
236
  queryWorkoutSamplesWithAnchor: exports.queryWorkoutSamplesWithAnchor,
231
237
  querySources: exports.querySources,
@@ -46,6 +46,8 @@ export const queryQuantitySamples = QuantityTypes.queryQuantitySamples.bind(Quan
46
46
  export const queryQuantitySamplesWithAnchor = QuantityTypes.queryQuantitySamplesWithAnchor.bind(QuantityTypes);
47
47
  export const queryStatisticsForQuantity = QuantityTypes.queryStatisticsForQuantity.bind(QuantityTypes);
48
48
  export const queryStatisticsCollectionForQuantity = QuantityTypes.queryStatisticsCollectionForQuantity.bind(QuantityTypes);
49
+ export const queryStatisticsForQuantitySeparateBySource = QuantityTypes.queryStatisticsForQuantitySeparateBySource.bind(QuantityTypes);
50
+ export const queryStatisticsCollectionForQuantitySeparateBySource = QuantityTypes.queryStatisticsCollectionForQuantitySeparateBySource.bind(QuantityTypes);
49
51
  export const queryWorkoutSamples = Workouts.queryWorkoutSamples.bind(Workouts);
50
52
  export const queryWorkoutSamplesWithAnchor = Workouts.queryWorkoutSamplesWithAnchor.bind(Workouts);
51
53
  export const querySources = Core.querySources.bind(Core);
@@ -115,6 +117,8 @@ export default {
115
117
  queryQuantitySamplesWithAnchor,
116
118
  queryStatisticsForQuantity,
117
119
  queryStatisticsCollectionForQuantity,
120
+ queryStatisticsForQuantitySeparateBySource,
121
+ queryStatisticsCollectionForQuantitySeparateBySource,
118
122
  queryWorkoutSamples,
119
123
  queryWorkoutSamplesWithAnchor,
120
124
  querySources,