@kingstinct/react-native-healthkit 11.1.1 → 11.1.2

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.
@@ -24,6 +24,7 @@ let HKWorkoutTypeIdentifier = "HKWorkoutTypeIdentifier"
24
24
  let HKWorkoutRouteTypeIdentifier = "HKWorkoutRouteTypeIdentifier"
25
25
  let HKDataTypeIdentifierHeartbeatSeries = "HKDataTypeIdentifierHeartbeatSeries"
26
26
  let HKStateOfMindTypeIdentifier = "HKStateOfMindTypeIdentifier"
27
+ let HKElectrocardiogramType = "HKElectrocardiogramType"
27
28
 
28
29
  let HKWorkoutActivityTypePropertyName = "activityType"
29
30
  let HKWorkoutSessionLocationTypePropertyName = "locationType"
@@ -9,7 +9,12 @@ import NitroModules
9
9
 
10
10
  var store = HKHealthStore.init()
11
11
 
12
- var quantityTypeUnitCache = [HKQuantityType: HKUnit]()
12
+ // Thread-safe cache with concurrent read/exclusive write access
13
+ private let quantityTypeCacheQueue = DispatchQueue(
14
+ label: "com.kingstinct.healthkit.cache",
15
+ attributes: .concurrent
16
+ )
17
+ private var quantityTypeUnitCache = [HKQuantityType: HKUnit]()
13
18
 
14
19
  func getUnitToUse(unitOverride: String?, quantityType: HKQuantityType) async throws -> HKUnit {
15
20
  if let unitOverride = unitOverride {
@@ -32,8 +37,11 @@ func getUnitToUse(unitOverride: String?, quantityType: HKQuantityType) async thr
32
37
  func getPreferredUnitsInternal(quantityTypes: [HKQuantityType], forceUpdate: Bool? = false) async throws -> [HKQuantityType: HKUnit] {
33
38
 
34
39
  if forceUpdate != true {
35
- let itemsInCache = quantityTypeUnitCache.filter { (quantityType: HKQuantityType, _: HKUnit) in
36
- return quantityTypes.contains(where: { $0 == quantityType })
40
+ // Thread-safe read: concurrent reads are allowed
41
+ let itemsInCache = quantityTypeCacheQueue.sync {
42
+ return quantityTypeUnitCache.filter {
43
+ quantityTypes.contains($0.key)
44
+ }
37
45
  }
38
46
  if itemsInCache.count == quantityTypes.count {
39
47
  return itemsInCache
@@ -47,8 +55,11 @@ func getPreferredUnitsInternal(quantityTypes: [HKQuantityType], forceUpdate: Boo
47
55
  return continuation.resume(throwing: error)
48
56
  }
49
57
 
50
- typePerUnits.forEach { (type: HKQuantityType, unit: HKUnit) in
51
- quantityTypeUnitCache.updateValue(unit, forKey: type)
58
+ // Thread-safe write: barrier ensures exclusive access
59
+ quantityTypeCacheQueue.sync(flags: .barrier) {
60
+ typePerUnits.forEach { (type: HKQuantityType, unit: HKUnit) in
61
+ quantityTypeUnitCache.updateValue(unit, forKey: type)
62
+ }
52
63
  }
53
64
 
54
65
  return continuation.resume(returning: typePerUnits)
package/ios/Helpers.swift CHANGED
@@ -413,6 +413,12 @@ private func sampleTypeFromStringNullable(typeIdentifier: String) throws -> HKSa
413
413
  }
414
414
  }
415
415
 
416
+ if #available(iOS 14, *) {
417
+ if typeIdentifier == HKElectrocardiogramType {
418
+ return HKSampleType.electrocardiogramType()
419
+ }
420
+ }
421
+
416
422
  #if compiler(>=6)
417
423
  if #available(iOS 18, *) {
418
424
  if typeIdentifier == HKStateOfMindTypeIdentifier {
@@ -26,9 +26,8 @@ const Characteristics_1 = require("./types/Characteristics");
26
26
  __exportStar(require("./types"), exports);
27
27
  const notAvailableError = `[@kingstinct/react-native-healthkit] Platform "${react_native_1.Platform.OS}" not supported. HealthKit is only available on iOS.`;
28
28
  let hasWarned = false;
29
- // @ts-ignore
30
29
  function UnavailableFnFromModule(_fn, defaultValue) {
31
- // @ts-ignore
30
+ // @ts-expect-error
32
31
  return () => {
33
32
  if (react_native_1.Platform.OS !== 'ios' && !hasWarned) {
34
33
  console.warn(notAvailableError);
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.HeartbeatSeriesTypeIdentifier = exports.StateOfMindTypeIdentifier = exports.WorkoutRouteTypeIdentifier = exports.WorkoutTypeIdentifier = void 0;
3
+ exports.ElectrocardiogramTypeIdentifier = exports.HeartbeatSeriesTypeIdentifier = exports.StateOfMindTypeIdentifier = exports.WorkoutRouteTypeIdentifier = exports.WorkoutTypeIdentifier = void 0;
4
4
  /**
5
5
  * Represents a workout type identifier.
6
6
  * @see {@link https://developer.apple.com/documentation/healthkit/hkworkouttypeidentifier Apple Docs HKWorkoutTypeIdentifier}
@@ -17,7 +17,12 @@ exports.WorkoutRouteTypeIdentifier = 'HKWorkoutRouteTypeIdentifier';
17
17
  */
18
18
  exports.StateOfMindTypeIdentifier = 'HKStateOfMindTypeIdentifier';
19
19
  /**
20
- * Represents a series sample containing heartbeat data..
20
+ * Represents a series sample containing heartbeat data.
21
21
  * @see {@link https://developer.apple.com/documentation/healthkit/HKDataTypeIdentifierHeartbeatSeries Apple Docs DataTypeIdentifierHeartbeatSeries}
22
22
  */
23
23
  exports.HeartbeatSeriesTypeIdentifier = 'HKDataTypeIdentifierHeartbeatSeries';
24
+ /**
25
+ * A type that identifies samples containing electrocardiogram data.
26
+ * @see {@link https://developer.apple.com/documentation/healthkit/hkelectrocardiogramtype Apple Docs HKElectrocardiogramType}
27
+ */
28
+ exports.ElectrocardiogramTypeIdentifier = 'HKElectrocardiogramType';
@@ -4,9 +4,8 @@ import { BiologicalSex, BloodType, FitzpatrickSkinType, WheelchairUse, } from '.
4
4
  export * from './types';
5
5
  const notAvailableError = `[@kingstinct/react-native-healthkit] Platform "${Platform.OS}" not supported. HealthKit is only available on iOS.`;
6
6
  let hasWarned = false;
7
- // @ts-ignore
8
7
  function UnavailableFnFromModule(_fn, defaultValue) {
9
- // @ts-ignore
8
+ // @ts-expect-error
10
9
  return () => {
11
10
  if (Platform.OS !== 'ios' && !hasWarned) {
12
11
  console.warn(notAvailableError);
@@ -14,7 +14,12 @@ export const WorkoutRouteTypeIdentifier = 'HKWorkoutRouteTypeIdentifier';
14
14
  */
15
15
  export const StateOfMindTypeIdentifier = 'HKStateOfMindTypeIdentifier';
16
16
  /**
17
- * Represents a series sample containing heartbeat data..
17
+ * Represents a series sample containing heartbeat data.
18
18
  * @see {@link https://developer.apple.com/documentation/healthkit/HKDataTypeIdentifierHeartbeatSeries Apple Docs DataTypeIdentifierHeartbeatSeries}
19
19
  */
20
20
  export const HeartbeatSeriesTypeIdentifier = 'HKDataTypeIdentifierHeartbeatSeries';
21
+ /**
22
+ * A type that identifies samples containing electrocardiogram data.
23
+ * @see {@link https://developer.apple.com/documentation/healthkit/hkelectrocardiogramtype Apple Docs HKElectrocardiogramType}
24
+ */
25
+ export const ElectrocardiogramTypeIdentifier = 'HKElectrocardiogramType';
@@ -14,7 +14,12 @@ export declare const WorkoutRouteTypeIdentifier: "HKWorkoutRouteTypeIdentifier";
14
14
  */
15
15
  export declare const StateOfMindTypeIdentifier: "HKStateOfMindTypeIdentifier";
16
16
  /**
17
- * Represents a series sample containing heartbeat data..
17
+ * Represents a series sample containing heartbeat data.
18
18
  * @see {@link https://developer.apple.com/documentation/healthkit/HKDataTypeIdentifierHeartbeatSeries Apple Docs DataTypeIdentifierHeartbeatSeries}
19
19
  */
20
20
  export declare const HeartbeatSeriesTypeIdentifier: "HKDataTypeIdentifierHeartbeatSeries";
21
+ /**
22
+ * A type that identifies samples containing electrocardiogram data.
23
+ * @see {@link https://developer.apple.com/documentation/healthkit/hkelectrocardiogramtype Apple Docs HKElectrocardiogramType}
24
+ */
25
+ export declare const ElectrocardiogramTypeIdentifier: "HKElectrocardiogramType";
@@ -1,7 +1,7 @@
1
1
  import type { AnyMap } from 'react-native-nitro-modules';
2
2
  import type { CategoryTypeIdentifier, CategoryTypeIdentifierWriteable } from './CategoryTypeIdentifier';
3
3
  import type { CharacteristicTypeIdentifier } from './Characteristics';
4
- import type { HeartbeatSeriesTypeIdentifier, StateOfMindTypeIdentifier, WorkoutRouteTypeIdentifier, WorkoutTypeIdentifier } from './Constants';
4
+ import type { ElectrocardiogramTypeIdentifier, HeartbeatSeriesTypeIdentifier, StateOfMindTypeIdentifier, WorkoutRouteTypeIdentifier, WorkoutTypeIdentifier } from './Constants';
5
5
  import type { CorrelationTypeIdentifier } from './CorrelationType';
6
6
  import type { QuantityTypeIdentifier, QuantityTypeIdentifierWriteable } from './QuantityTypeIdentifier';
7
7
  export interface GenericMetadata {
@@ -25,7 +25,7 @@ export interface DeletedSample {
25
25
  readonly metadata?: AnyMap;
26
26
  }
27
27
  export type ObjectTypeIdentifier = CharacteristicTypeIdentifier | SampleTypeIdentifier | typeof ActivitySummaryTypeIdentifier;
28
- export type SampleTypeIdentifier = CategoryTypeIdentifier | CorrelationTypeIdentifier | QuantityTypeIdentifier | typeof StateOfMindTypeIdentifier | typeof AudiogramTypeIdentifier | typeof HeartbeatSeriesTypeIdentifier | typeof WorkoutRouteTypeIdentifier | typeof WorkoutTypeIdentifier;
28
+ export type SampleTypeIdentifier = CategoryTypeIdentifier | CorrelationTypeIdentifier | QuantityTypeIdentifier | typeof StateOfMindTypeIdentifier | typeof AudiogramTypeIdentifier | typeof HeartbeatSeriesTypeIdentifier | typeof WorkoutRouteTypeIdentifier | typeof WorkoutTypeIdentifier | typeof ElectrocardiogramTypeIdentifier;
29
29
  export type SampleTypeIdentifierWriteable = CategoryTypeIdentifierWriteable | CorrelationTypeIdentifier | QuantityTypeIdentifierWriteable | typeof StateOfMindTypeIdentifier | typeof AudiogramTypeIdentifier | typeof HeartbeatSeriesTypeIdentifier | typeof WorkoutRouteTypeIdentifier | typeof WorkoutTypeIdentifier;
30
30
  /**
31
31
  * Represents a type that identifies activity summary objects.
@@ -409,6 +409,8 @@ public extension ObjectTypeIdentifier {
409
409
  self = .hkworkoutroutetypeidentifier
410
410
  case "HKWorkoutTypeIdentifier":
411
411
  self = .hkworkouttypeidentifier
412
+ case "HKElectrocardiogramType":
413
+ self = .hkelectrocardiogramtype
412
414
  case "ActivitySummaryTypeIdentifier":
413
415
  self = .activitysummarytypeidentifier
414
416
  default:
@@ -813,6 +815,8 @@ public extension ObjectTypeIdentifier {
813
815
  return "HKWorkoutRouteTypeIdentifier"
814
816
  case .hkworkouttypeidentifier:
815
817
  return "HKWorkoutTypeIdentifier"
818
+ case .hkelectrocardiogramtype:
819
+ return "HKElectrocardiogramType"
816
820
  case .activitysummarytypeidentifier:
817
821
  return "ActivitySummaryTypeIdentifier"
818
822
  }
@@ -397,6 +397,8 @@ public extension SampleTypeIdentifier {
397
397
  self = .hkworkoutroutetypeidentifier
398
398
  case "HKWorkoutTypeIdentifier":
399
399
  self = .hkworkouttypeidentifier
400
+ case "HKElectrocardiogramType":
401
+ self = .hkelectrocardiogramtype
400
402
  default:
401
403
  return nil
402
404
  }
@@ -787,6 +789,8 @@ public extension SampleTypeIdentifier {
787
789
  return "HKWorkoutRouteTypeIdentifier"
788
790
  case .hkworkouttypeidentifier:
789
791
  return "HKWorkoutTypeIdentifier"
792
+ case .hkelectrocardiogramtype:
793
+ return "HKElectrocardiogramType"
790
794
  }
791
795
  }
792
796
  }
@@ -225,7 +225,8 @@ namespace margelo::nitro::healthkit {
225
225
  HKDATATYPEIDENTIFIERHEARTBEATSERIES SWIFT_NAME(hkdatatypeidentifierheartbeatseries) = 193,
226
226
  HKWORKOUTROUTETYPEIDENTIFIER SWIFT_NAME(hkworkoutroutetypeidentifier) = 194,
227
227
  HKWORKOUTTYPEIDENTIFIER SWIFT_NAME(hkworkouttypeidentifier) = 195,
228
- ACTIVITYSUMMARYTYPEIDENTIFIER SWIFT_NAME(activitysummarytypeidentifier) = 196,
228
+ HKELECTROCARDIOGRAMTYPE SWIFT_NAME(hkelectrocardiogramtype) = 196,
229
+ ACTIVITYSUMMARYTYPEIDENTIFIER SWIFT_NAME(activitysummarytypeidentifier) = 197,
229
230
  } CLOSED_ENUM;
230
231
 
231
232
  } // namespace margelo::nitro::healthkit
@@ -434,6 +435,7 @@ namespace margelo::nitro {
434
435
  case hashString("HKDataTypeIdentifierHeartbeatSeries"): return margelo::nitro::healthkit::ObjectTypeIdentifier::HKDATATYPEIDENTIFIERHEARTBEATSERIES;
435
436
  case hashString("HKWorkoutRouteTypeIdentifier"): return margelo::nitro::healthkit::ObjectTypeIdentifier::HKWORKOUTROUTETYPEIDENTIFIER;
436
437
  case hashString("HKWorkoutTypeIdentifier"): return margelo::nitro::healthkit::ObjectTypeIdentifier::HKWORKOUTTYPEIDENTIFIER;
438
+ case hashString("HKElectrocardiogramType"): return margelo::nitro::healthkit::ObjectTypeIdentifier::HKELECTROCARDIOGRAMTYPE;
437
439
  case hashString("ActivitySummaryTypeIdentifier"): return margelo::nitro::healthkit::ObjectTypeIdentifier::ACTIVITYSUMMARYTYPEIDENTIFIER;
438
440
  default: [[unlikely]]
439
441
  throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum ObjectTypeIdentifier - invalid value!");
@@ -637,6 +639,7 @@ namespace margelo::nitro {
637
639
  case margelo::nitro::healthkit::ObjectTypeIdentifier::HKDATATYPEIDENTIFIERHEARTBEATSERIES: return JSIConverter<std::string>::toJSI(runtime, "HKDataTypeIdentifierHeartbeatSeries");
638
640
  case margelo::nitro::healthkit::ObjectTypeIdentifier::HKWORKOUTROUTETYPEIDENTIFIER: return JSIConverter<std::string>::toJSI(runtime, "HKWorkoutRouteTypeIdentifier");
639
641
  case margelo::nitro::healthkit::ObjectTypeIdentifier::HKWORKOUTTYPEIDENTIFIER: return JSIConverter<std::string>::toJSI(runtime, "HKWorkoutTypeIdentifier");
642
+ case margelo::nitro::healthkit::ObjectTypeIdentifier::HKELECTROCARDIOGRAMTYPE: return JSIConverter<std::string>::toJSI(runtime, "HKElectrocardiogramType");
640
643
  case margelo::nitro::healthkit::ObjectTypeIdentifier::ACTIVITYSUMMARYTYPEIDENTIFIER: return JSIConverter<std::string>::toJSI(runtime, "ActivitySummaryTypeIdentifier");
641
644
  default: [[unlikely]]
642
645
  throw std::invalid_argument("Cannot convert ObjectTypeIdentifier to JS - invalid value: "
@@ -845,6 +848,7 @@ namespace margelo::nitro {
845
848
  case hashString("HKDataTypeIdentifierHeartbeatSeries"):
846
849
  case hashString("HKWorkoutRouteTypeIdentifier"):
847
850
  case hashString("HKWorkoutTypeIdentifier"):
851
+ case hashString("HKElectrocardiogramType"):
848
852
  case hashString("ActivitySummaryTypeIdentifier"):
849
853
  return true;
850
854
  default:
@@ -219,6 +219,7 @@ namespace margelo::nitro::healthkit {
219
219
  HKDATATYPEIDENTIFIERHEARTBEATSERIES SWIFT_NAME(hkdatatypeidentifierheartbeatseries) = 187,
220
220
  HKWORKOUTROUTETYPEIDENTIFIER SWIFT_NAME(hkworkoutroutetypeidentifier) = 188,
221
221
  HKWORKOUTTYPEIDENTIFIER SWIFT_NAME(hkworkouttypeidentifier) = 189,
222
+ HKELECTROCARDIOGRAMTYPE SWIFT_NAME(hkelectrocardiogramtype) = 190,
222
223
  } CLOSED_ENUM;
223
224
 
224
225
  } // namespace margelo::nitro::healthkit
@@ -421,6 +422,7 @@ namespace margelo::nitro {
421
422
  case hashString("HKDataTypeIdentifierHeartbeatSeries"): return margelo::nitro::healthkit::SampleTypeIdentifier::HKDATATYPEIDENTIFIERHEARTBEATSERIES;
422
423
  case hashString("HKWorkoutRouteTypeIdentifier"): return margelo::nitro::healthkit::SampleTypeIdentifier::HKWORKOUTROUTETYPEIDENTIFIER;
423
424
  case hashString("HKWorkoutTypeIdentifier"): return margelo::nitro::healthkit::SampleTypeIdentifier::HKWORKOUTTYPEIDENTIFIER;
425
+ case hashString("HKElectrocardiogramType"): return margelo::nitro::healthkit::SampleTypeIdentifier::HKELECTROCARDIOGRAMTYPE;
424
426
  default: [[unlikely]]
425
427
  throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum SampleTypeIdentifier - invalid value!");
426
428
  }
@@ -617,6 +619,7 @@ namespace margelo::nitro {
617
619
  case margelo::nitro::healthkit::SampleTypeIdentifier::HKDATATYPEIDENTIFIERHEARTBEATSERIES: return JSIConverter<std::string>::toJSI(runtime, "HKDataTypeIdentifierHeartbeatSeries");
618
620
  case margelo::nitro::healthkit::SampleTypeIdentifier::HKWORKOUTROUTETYPEIDENTIFIER: return JSIConverter<std::string>::toJSI(runtime, "HKWorkoutRouteTypeIdentifier");
619
621
  case margelo::nitro::healthkit::SampleTypeIdentifier::HKWORKOUTTYPEIDENTIFIER: return JSIConverter<std::string>::toJSI(runtime, "HKWorkoutTypeIdentifier");
622
+ case margelo::nitro::healthkit::SampleTypeIdentifier::HKELECTROCARDIOGRAMTYPE: return JSIConverter<std::string>::toJSI(runtime, "HKElectrocardiogramType");
620
623
  default: [[unlikely]]
621
624
  throw std::invalid_argument("Cannot convert SampleTypeIdentifier to JS - invalid value: "
622
625
  + std::to_string(static_cast<int>(arg)) + "!");
@@ -818,6 +821,7 @@ namespace margelo::nitro {
818
821
  case hashString("HKDataTypeIdentifierHeartbeatSeries"):
819
822
  case hashString("HKWorkoutRouteTypeIdentifier"):
820
823
  case hashString("HKWorkoutTypeIdentifier"):
824
+ case hashString("HKElectrocardiogramType"):
821
825
  return true;
822
826
  default:
823
827
  return false;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kingstinct/react-native-healthkit",
3
- "version": "11.1.1",
3
+ "version": "11.1.2",
4
4
  "description": "React Native bindings for HealthKit",
5
5
  "main": "lib/commonjs/index.js",
6
6
  "module": "lib/module/index.js",
package/src/healthkit.ts CHANGED
@@ -32,15 +32,13 @@ const notAvailableError = `[@kingstinct/react-native-healthkit] Platform "${Plat
32
32
 
33
33
  let hasWarned = false
34
34
 
35
- // @ts-ignore
36
35
  function UnavailableFnFromModule<
37
36
  TKey extends keyof typeof ReactNativeHealthkit,
38
- // @ts-ignore
39
37
  // biome-ignore lint/complexity/noBannedTypes: it works
40
38
  T extends Function = (typeof ReactNativeHealthkit)[TKey],
41
- // @ts-ignore
39
+ // @ts-expect-error
42
40
  >(_fn: TKey, defaultValue: ReturnType<T>): T {
43
- // @ts-ignore
41
+ // @ts-expect-error
44
42
  return () => {
45
43
  if (Platform.OS !== 'ios' && !hasWarned) {
46
44
  console.warn(notAvailableError)
@@ -18,8 +18,15 @@ export const WorkoutRouteTypeIdentifier =
18
18
  export const StateOfMindTypeIdentifier = 'HKStateOfMindTypeIdentifier' as const
19
19
 
20
20
  /**
21
- * Represents a series sample containing heartbeat data..
21
+ * Represents a series sample containing heartbeat data.
22
22
  * @see {@link https://developer.apple.com/documentation/healthkit/HKDataTypeIdentifierHeartbeatSeries Apple Docs DataTypeIdentifierHeartbeatSeries}
23
23
  */
24
24
  export const HeartbeatSeriesTypeIdentifier =
25
25
  'HKDataTypeIdentifierHeartbeatSeries' as const
26
+
27
+ /**
28
+ * A type that identifies samples containing electrocardiogram data.
29
+ * @see {@link https://developer.apple.com/documentation/healthkit/hkelectrocardiogramtype Apple Docs HKElectrocardiogramType}
30
+ */
31
+ export const ElectrocardiogramTypeIdentifier =
32
+ 'HKElectrocardiogramType' as const
@@ -5,6 +5,7 @@ import type {
5
5
  } from './CategoryTypeIdentifier'
6
6
  import type { CharacteristicTypeIdentifier } from './Characteristics'
7
7
  import type {
8
+ ElectrocardiogramTypeIdentifier,
8
9
  HeartbeatSeriesTypeIdentifier,
9
10
  StateOfMindTypeIdentifier,
10
11
  WorkoutRouteTypeIdentifier,
@@ -52,6 +53,7 @@ export type SampleTypeIdentifier =
52
53
  | typeof HeartbeatSeriesTypeIdentifier
53
54
  | typeof WorkoutRouteTypeIdentifier
54
55
  | typeof WorkoutTypeIdentifier
56
+ | typeof ElectrocardiogramTypeIdentifier
55
57
 
56
58
  export type SampleTypeIdentifierWriteable =
57
59
  | CategoryTypeIdentifierWriteable