@kingstinct/react-native-healthkit 14.1.0 → 16.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 (123) hide show
  1. package/README.md +37 -3
  2. package/ReactNativeHealthkit.podspec +11 -7
  3. package/app.plugin.js +33 -94
  4. package/app.plugin.ts +29 -104
  5. package/ios/CategoryTypeModule.swift +1 -0
  6. package/ios/CharacteristicTypeModule.swift +7 -6
  7. package/ios/Constants.swift +9 -10
  8. package/ios/CoreModule.swift +77 -42
  9. package/ios/CorrelationTypeModule.swift +3 -2
  10. package/ios/ElectrocardiogramModule.swift +4 -3
  11. package/ios/HeartbeatSeriesModule.swift +4 -3
  12. package/ios/Helpers.swift +11 -216
  13. package/ios/MedicationModule.swift +9 -8
  14. package/ios/MemoryEstimation.swift +84 -0
  15. package/ios/PredicateHelpers.swift +16 -86
  16. package/ios/QuantityTypeModule.swift +37 -28
  17. package/ios/Serializers.swift +34 -70
  18. package/ios/SourceProxy.swift +15 -5
  19. package/ios/StateOfMindModule.swift +3 -2
  20. package/ios/WorkoutProxy.swift +31 -13
  21. package/ios/WorkoutsModule.swift +4 -3
  22. package/lib/commonjs/generated/healthkit.generated.js +15 -3
  23. package/lib/commonjs/healthkit.ios.js +6 -2
  24. package/lib/commonjs/healthkit.js +24 -79
  25. package/lib/commonjs/types/Auth.js +3 -18
  26. package/lib/commonjs/types/Background.js +2 -10
  27. package/lib/commonjs/types/QueryOptions.js +2 -17
  28. package/lib/module/generated/healthkit.generated.js +14 -2
  29. package/lib/module/healthkit.ios.js +4 -0
  30. package/lib/module/healthkit.js +22 -77
  31. package/lib/module/types/Auth.js +1 -18
  32. package/lib/module/types/Background.js +1 -10
  33. package/lib/module/types/QueryOptions.js +1 -17
  34. package/lib/typescript/generated/healthkit.generated.d.ts +20 -7
  35. package/lib/typescript/healthkit.d.ts +4 -2
  36. package/lib/typescript/healthkit.ios.d.ts +13 -9
  37. package/lib/typescript/specs/CoreModule.nitro.d.ts +22 -4
  38. package/lib/typescript/specs/SourceProxy.nitro.d.ts +2 -5
  39. package/lib/typescript/types/Auth.d.ts +1 -16
  40. package/lib/typescript/types/Background.d.ts +1 -9
  41. package/lib/typescript/types/Device.d.ts +1 -13
  42. package/lib/typescript/types/QuantityType.d.ts +3 -3
  43. package/lib/typescript/types/QueryOptions.d.ts +3 -37
  44. package/lib/typescript/types/Shared.d.ts +2 -25
  45. package/lib/typescript/types/Source.d.ts +1 -10
  46. package/lib/typescript/types/Subscriptions.d.ts +2 -3
  47. package/lib/typescript/types/Units.d.ts +1 -1
  48. package/nitrogen/generated/ios/ReactNativeHealthkit-Swift-Cxx-Bridge.cpp +24 -16
  49. package/nitrogen/generated/ios/ReactNativeHealthkit-Swift-Cxx-Bridge.hpp +91 -12
  50. package/nitrogen/generated/ios/c++/HybridCategoryTypeModuleSpecSwift.hpp +8 -5
  51. package/nitrogen/generated/ios/c++/HybridCoreModuleSpecSwift.hpp +8 -0
  52. package/nitrogen/generated/ios/c++/HybridCorrelationTypeModuleSpecSwift.hpp +8 -5
  53. package/nitrogen/generated/ios/c++/HybridElectrocardiogramModuleSpecSwift.hpp +8 -5
  54. package/nitrogen/generated/ios/c++/HybridHeartbeatSeriesModuleSpecSwift.hpp +8 -5
  55. package/nitrogen/generated/ios/c++/HybridMedicationModuleSpecSwift.hpp +8 -5
  56. package/nitrogen/generated/ios/c++/HybridQuantityTypeModuleSpecSwift.hpp +8 -5
  57. package/nitrogen/generated/ios/c++/HybridStateOfMindModuleSpecSwift.hpp +8 -5
  58. package/nitrogen/generated/ios/c++/HybridWorkoutProxySpecSwift.hpp +3 -4
  59. package/nitrogen/generated/ios/c++/HybridWorkoutsModuleSpecSwift.hpp +6 -3
  60. package/nitrogen/generated/ios/swift/CategorySample.swift +8 -8
  61. package/nitrogen/generated/ios/swift/CategoryTypeIdentifier.swift +8 -0
  62. package/nitrogen/generated/ios/swift/CategoryTypeIdentifierWriteable.swift +8 -0
  63. package/nitrogen/generated/ios/swift/CorrelationSample.swift +8 -8
  64. package/nitrogen/generated/ios/swift/ElectrocardiogramSample.swift +8 -8
  65. package/nitrogen/generated/ios/swift/Func_void_std__unordered_map_std__string__std__chrono__system_clock__time_point_.swift +54 -0
  66. package/nitrogen/generated/ios/swift/HeartbeatSeriesSample.swift +8 -8
  67. package/nitrogen/generated/ios/swift/HybridCoreModuleSpec.swift +1 -0
  68. package/nitrogen/generated/ios/swift/HybridCoreModuleSpec_cxx.swift +25 -0
  69. package/nitrogen/generated/ios/swift/MedicationDoseEvent.swift +8 -8
  70. package/nitrogen/generated/ios/swift/ObjectTypeIdentifier.swift +12 -4
  71. package/nitrogen/generated/ios/swift/QuantitySample.swift +8 -8
  72. package/nitrogen/generated/ios/swift/QuantityTypeIdentifier.swift +4 -4
  73. package/nitrogen/generated/ios/swift/QuantityTypeIdentifierWriteable.swift +4 -4
  74. package/nitrogen/generated/ios/swift/QueryStatisticsResponse.swift +6 -13
  75. package/nitrogen/generated/ios/swift/QueryStatisticsResponseFromSingleSource.swift +4 -11
  76. package/nitrogen/generated/ios/swift/SampleTypeIdentifier.swift +12 -4
  77. package/nitrogen/generated/ios/swift/SampleTypeIdentifierWriteable.swift +12 -4
  78. package/nitrogen/generated/ios/swift/SourceRevision.swift +4 -11
  79. package/nitrogen/generated/ios/swift/StateOfMindSample.swift +8 -8
  80. package/nitrogen/generated/ios/swift/WorkoutActivityType.swift +8 -0
  81. package/nitrogen/generated/shared/c++/CategorySample.hpp +7 -7
  82. package/nitrogen/generated/shared/c++/CategoryTypeIdentifier.hpp +67 -59
  83. package/nitrogen/generated/shared/c++/CategoryTypeIdentifierWriteable.hpp +67 -59
  84. package/nitrogen/generated/shared/c++/CorrelationSample.hpp +7 -7
  85. package/nitrogen/generated/shared/c++/ElectrocardiogramSample.hpp +7 -7
  86. package/nitrogen/generated/shared/c++/HeartbeatSeriesSample.hpp +7 -7
  87. package/nitrogen/generated/shared/c++/HybridCoreModuleSpec.cpp +1 -0
  88. package/nitrogen/generated/shared/c++/HybridCoreModuleSpec.hpp +3 -1
  89. package/nitrogen/generated/shared/c++/MedicationDoseEvent.hpp +7 -7
  90. package/nitrogen/generated/shared/c++/ObjectTypeIdentifier.hpp +206 -198
  91. package/nitrogen/generated/shared/c++/QuantitySample.hpp +7 -7
  92. package/nitrogen/generated/shared/c++/QuantityTypeIdentifier.hpp +73 -73
  93. package/nitrogen/generated/shared/c++/QuantityTypeIdentifierWriteable.hpp +73 -73
  94. package/nitrogen/generated/shared/c++/QueryStatisticsResponse.hpp +8 -9
  95. package/nitrogen/generated/shared/c++/QueryStatisticsResponseFromSingleSource.hpp +8 -9
  96. package/nitrogen/generated/shared/c++/SampleTypeIdentifier.hpp +199 -191
  97. package/nitrogen/generated/shared/c++/SampleTypeIdentifierWriteable.hpp +193 -185
  98. package/nitrogen/generated/shared/c++/SourceRevision.hpp +8 -9
  99. package/nitrogen/generated/shared/c++/StateOfMindSample.hpp +7 -7
  100. package/nitrogen/generated/shared/c++/WorkoutActivityType.hpp +4 -0
  101. package/package.json +8 -3
  102. package/src/generated/healthkit-schema.json +53 -8
  103. package/src/generated/healthkit.generated.ts +22 -6
  104. package/src/healthkit.ios.ts +6 -0
  105. package/src/healthkit.ts +32 -84
  106. package/src/specs/CoreModule.nitro.ts +25 -4
  107. package/src/specs/SourceProxy.nitro.ts +2 -4
  108. package/src/test-setup.ts +1 -0
  109. package/src/type-tests/generated-typing.ts +30 -8
  110. package/src/types/Auth.ts +4 -17
  111. package/src/types/Background.ts +1 -9
  112. package/src/types/Device.ts +1 -13
  113. package/src/types/QuantityType.ts +3 -3
  114. package/src/types/QueryOptions.ts +7 -65
  115. package/src/types/Shared.ts +7 -28
  116. package/src/types/Source.ts +1 -11
  117. package/src/types/Subscriptions.ts +2 -3
  118. package/src/types/Units.ts +1 -1
  119. package/ios/BackgroundDeliveryManager.swift +0 -277
  120. package/ios/Bridge.h +0 -10
  121. package/ios/ExceptionCatcher.h +0 -5
  122. package/ios/ExceptionCatcher.mm +0 -32
  123. package/ios/module.modulemap +0 -5
package/src/healthkit.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { Platform } from 'react-native'
1
+ import { createUnavailableHelpers } from '@react-native-healthkit/core'
2
2
 
3
3
  // Import types for default values and function signatures.
4
4
  // These types are expected to be available via the './types' export.
@@ -52,25 +52,10 @@ import type {
52
52
 
53
53
  export * from './types'
54
54
 
55
- const notAvailableError = `[@kingstinct/react-native-healthkit] Platform "${Platform.OS}" not supported. HealthKit is only available on iOS.`
56
-
57
- let hasWarned = false
58
-
59
- function UnavailableFnFromModule<
60
- TKey extends keyof typeof ReactNativeHealthkit,
61
- // biome-ignore lint/complexity/noBannedTypes: it works
62
- T extends Function = (typeof ReactNativeHealthkit)[TKey],
63
- // @ts-expect-error
64
- >(_fn: TKey, defaultValue: ReturnType<T>): T {
65
- // @ts-expect-error
66
- return () => {
67
- if (Platform.OS !== 'ios' && !hasWarned) {
68
- console.warn(notAvailableError)
69
- hasWarned = true
70
- }
71
- return defaultValue
72
- }
73
- }
55
+ const { unavailableFn: UnavailableFnFromModule, warnIfUnavailable } =
56
+ createUnavailableHelpers<typeof ReactNativeHealthkit>(
57
+ '@kingstinct/react-native-healthkit',
58
+ )
74
59
 
75
60
  // --- Mock Implementations for exported functions ---
76
61
 
@@ -137,6 +122,10 @@ export const isProtectedDataAvailable = UnavailableFnFromModule(
137
122
  'isProtectedDataAvailable',
138
123
  false,
139
124
  )
125
+ export const isProtectedDataAvailableAsync = UnavailableFnFromModule(
126
+ 'isProtectedDataAvailableAsync',
127
+ Promise.resolve(false),
128
+ )
140
129
  export const isObjectTypeAvailable = UnavailableFnFromModule(
141
130
  'isObjectTypeAvailable',
142
131
  false,
@@ -181,10 +170,7 @@ export function queryQuantitySamples<T extends QuantityTypeIdentifier>(
181
170
  _identifier: T,
182
171
  _options: QueryOptionsWithSortOrderAndUnit<UnitForIdentifier<T>>,
183
172
  ): Promise<readonly QuantitySampleTyped<T>[]> {
184
- if (Platform.OS !== 'ios' && !hasWarned) {
185
- console.warn(notAvailableError)
186
- hasWarned = true
187
- }
173
+ warnIfUnavailable()
188
174
  return Promise.resolve([])
189
175
  }
190
176
 
@@ -194,10 +180,7 @@ export function queryQuantitySamplesWithAnchor<
194
180
  _identifier: T,
195
181
  _options: QueryOptionsWithAnchorAndUnit<UnitForIdentifier<T>>,
196
182
  ): Promise<QuantitySamplesWithAnchorResponseTyped<T>> {
197
- if (Platform.OS !== 'ios' && !hasWarned) {
198
- console.warn(notAvailableError)
199
- hasWarned = true
200
- }
183
+ warnIfUnavailable()
201
184
  return Promise.resolve({
202
185
  samples: [],
203
186
  deletedSamples: [],
@@ -209,10 +192,7 @@ export function queryStatisticsForQuantity<T extends QuantityTypeIdentifier>(
209
192
  _statistics: readonly StatisticsOptions[],
210
193
  _options?: StatisticsQueryOptions<UnitForIdentifier<T>>,
211
194
  ): Promise<QueryStatisticsResponse> {
212
- if (Platform.OS !== 'ios' && !hasWarned) {
213
- console.warn(notAvailableError)
214
- hasWarned = true
215
- }
195
+ warnIfUnavailable()
216
196
  return Promise.resolve({
217
197
  sources: [],
218
198
  })
@@ -226,10 +206,7 @@ export function queryStatisticsCollectionForQuantity<
226
206
  _intervalComponents: IntervalComponents,
227
207
  _options?: StatisticsQueryOptions<UnitForIdentifier<T>>,
228
208
  ): Promise<readonly QueryStatisticsResponse[]> {
229
- if (Platform.OS !== 'ios' && !hasWarned) {
230
- console.warn(notAvailableError)
231
- hasWarned = true
232
- }
209
+ warnIfUnavailable()
233
210
  return Promise.resolve([])
234
211
  }
235
212
 
@@ -240,10 +217,7 @@ export function queryStatisticsForQuantitySeparateBySource<
240
217
  _statistics: readonly StatisticsOptions[],
241
218
  _options?: StatisticsQueryOptions<UnitForIdentifier<T>>,
242
219
  ): Promise<QueryStatisticsResponseFromSingleSource[]> {
243
- if (Platform.OS !== 'ios' && !hasWarned) {
244
- console.warn(notAvailableError)
245
- hasWarned = true
246
- }
220
+ warnIfUnavailable()
247
221
  return Promise.resolve([])
248
222
  }
249
223
  export function queryStatisticsCollectionForQuantitySeparateBySource<
@@ -255,10 +229,7 @@ export function queryStatisticsCollectionForQuantitySeparateBySource<
255
229
  _intervalComponents: IntervalComponents,
256
230
  _options?: StatisticsQueryOptions<UnitForIdentifier<T>>,
257
231
  ): Promise<readonly QueryStatisticsResponseFromSingleSource[]> {
258
- if (Platform.OS !== 'ios' && !hasWarned) {
259
- console.warn(notAvailableError)
260
- hasWarned = true
261
- }
232
+ warnIfUnavailable()
262
233
  return Promise.resolve([])
263
234
  }
264
235
  export function saveQuantitySample<T extends QuantityTypeIdentifierWriteable>(
@@ -269,20 +240,14 @@ export function saveQuantitySample<T extends QuantityTypeIdentifierWriteable>(
269
240
  _end: Date,
270
241
  _metadata?: MetadataForQuantityIdentifier<T>,
271
242
  ): Promise<QuantitySampleTyped<T> | undefined> {
272
- if (Platform.OS !== 'ios' && !hasWarned) {
273
- console.warn(notAvailableError)
274
- hasWarned = true
275
- }
243
+ warnIfUnavailable()
276
244
  return Promise.resolve(undefined)
277
245
  }
278
246
  export function isQuantityCompatibleWithUnit<T extends QuantityTypeIdentifier>(
279
247
  _identifier: T,
280
248
  _unit: UnitForIdentifier<T>,
281
249
  ): boolean {
282
- if (Platform.OS !== 'ios' && !hasWarned) {
283
- console.warn(notAvailableError)
284
- hasWarned = true
285
- }
250
+ warnIfUnavailable()
286
251
  return false
287
252
  }
288
253
 
@@ -291,10 +256,7 @@ export function queryCategorySamples<T extends CategoryTypeIdentifier>(
291
256
  _categoryTypeIdentifier: T,
292
257
  _options: QueryOptionsWithSortOrder,
293
258
  ): Promise<CategorySampleTyped<T>[]> {
294
- if (Platform.OS !== 'ios' && !hasWarned) {
295
- console.warn(notAvailableError)
296
- hasWarned = true
297
- }
259
+ warnIfUnavailable()
298
260
  return Promise.resolve([])
299
261
  }
300
262
 
@@ -304,10 +266,7 @@ export function queryCategorySamplesWithAnchor<
304
266
  _categoryTypeIdentifier: T,
305
267
  _options: QueryOptionsWithAnchor,
306
268
  ): Promise<CategorySamplesWithAnchorResponseTyped<T>> {
307
- if (Platform.OS !== 'ios' && !hasWarned) {
308
- console.warn(notAvailableError)
309
- hasWarned = true
310
- }
269
+ warnIfUnavailable()
311
270
  return Promise.resolve({
312
271
  samples: [],
313
272
  deletedSamples: [],
@@ -322,10 +281,7 @@ export function saveCategorySample<T extends CategoryTypeIdentifierWriteable>(
322
281
  _endDate: Date,
323
282
  _metadata?: MetadataForCategoryIdentifier<T>,
324
283
  ): Promise<CategorySampleTyped<T> | undefined> {
325
- if (Platform.OS !== 'ios' && !hasWarned) {
326
- console.warn(notAvailableError)
327
- hasWarned = true
328
- }
284
+ warnIfUnavailable()
329
285
  return Promise.resolve(undefined)
330
286
  }
331
287
 
@@ -422,10 +378,7 @@ export const saveStateOfMindSample = UnavailableFnFromModule(
422
378
  export function getMostRecentCategorySample<T extends CategoryTypeIdentifier>(
423
379
  _identifier: T,
424
380
  ): Promise<CategorySampleTyped<T> | undefined> {
425
- if (Platform.OS !== 'ios' && !hasWarned) {
426
- console.warn(notAvailableError)
427
- hasWarned = true
428
- }
381
+ warnIfUnavailable()
429
382
  return Promise.resolve(undefined)
430
383
  }
431
384
 
@@ -433,10 +386,7 @@ export function getMostRecentQuantitySample<T extends QuantityTypeIdentifier>(
433
386
  _identifier: T,
434
387
  _unit?: UnitForIdentifier<T>,
435
388
  ): Promise<QuantitySampleTyped<T> | undefined> {
436
- if (Platform.OS !== 'ios' && !hasWarned) {
437
- console.warn(notAvailableError)
438
- hasWarned = true
439
- }
389
+ warnIfUnavailable()
440
390
  return Promise.resolve(undefined)
441
391
  }
442
392
  export const getMostRecentWorkout = UnavailableFnFromModule(
@@ -447,10 +397,7 @@ export const getMostRecentWorkout = UnavailableFnFromModule(
447
397
  export function getPreferredUnit<T extends QuantityTypeIdentifier>(
448
398
  _quantityType: T,
449
399
  ): Promise<UnitForIdentifier<T>> {
450
- if (Platform.OS !== 'ios' && !hasWarned) {
451
- console.warn(notAvailableError)
452
- hasWarned = true
453
- }
400
+ warnIfUnavailable()
454
401
  return Promise.resolve('count' as UnitForIdentifier<T>)
455
402
  }
456
403
 
@@ -458,10 +405,7 @@ export function getPreferredUnit<T extends QuantityTypeIdentifier>(
458
405
  export function useMostRecentCategorySample<T extends CategoryTypeIdentifier>(
459
406
  _categoryTypeIdentifier: T,
460
407
  ): CategorySampleTyped<T> | undefined {
461
- if (Platform.OS !== 'ios' && !hasWarned) {
462
- console.warn(notAvailableError)
463
- hasWarned = true
464
- }
408
+ warnIfUnavailable()
465
409
  return undefined
466
410
  }
467
411
 
@@ -469,10 +413,7 @@ export function useMostRecentQuantitySample<T extends QuantityTypeIdentifier>(
469
413
  _identifier: T,
470
414
  _unit?: UnitForIdentifier<T>,
471
415
  ): QuantitySampleTyped<T> | undefined {
472
- if (Platform.OS !== 'ios' && !hasWarned) {
473
- console.warn(notAvailableError)
474
- hasWarned = true
475
- }
416
+ warnIfUnavailable()
476
417
  return undefined
477
418
  }
478
419
  export const useMostRecentWorkout = UnavailableFnFromModule(
@@ -565,6 +506,11 @@ export const requestPerObjectReadAuthorization = UnavailableFnFromModule(
565
506
  Promise.resolve(undefined),
566
507
  ) // Mocking callback structure
567
508
 
509
+ export const getEarliestAuthorizedSampleDates = UnavailableFnFromModule(
510
+ 'getEarliestAuthorizedSampleDates',
511
+ Promise.resolve({}),
512
+ )
513
+
568
514
  export const subscribeToCategorySamples = UnavailableFnFromModule(
569
515
  'subscribeToCategorySamples',
570
516
  {
@@ -630,6 +576,7 @@ const HealthkitModule = {
630
576
  subscribeToChanges,
631
577
  startWatchApp,
632
578
  isProtectedDataAvailable,
579
+ isProtectedDataAvailableAsync,
633
580
  queryStateOfMindSamples,
634
581
  queryStateOfMindSamplesWithAnchor,
635
582
  saveStateOfMindSample,
@@ -641,6 +588,7 @@ const HealthkitModule = {
641
588
  queryMedicationEventsWithAnchor,
642
589
  requestMedicationsAuthorization,
643
590
  requestPerObjectReadAuthorization,
591
+ getEarliestAuthorizedSampleDates,
644
592
 
645
593
  subscribeToCategorySamples,
646
594
  currentAppSource,
@@ -41,13 +41,15 @@ export interface CoreModule extends HybridObject<{ ios: 'swift' }> {
41
41
  disableAllBackgroundDelivery(): Promise<boolean>
42
42
 
43
43
  /**
44
- * Configure background delivery types that will be registered natively in
45
- * AppDelegate.didFinishLaunchingWithOptions — surviving app termination.
44
+ * Configure background delivery types whose observer queries are registered
45
+ * natively at launch (during didFinishLaunchingWithOptions), so background
46
+ * delivery survives app termination.
46
47
  * Types and frequency are persisted to UserDefaults so they're available
47
48
  * before the JS bridge boots on subsequent cold launches.
48
49
  *
49
- * Requires the Expo config plugin with `background: true` (default) or
50
- * manual AppDelegate setup: `BackgroundDeliveryManager.shared.setupBackgroundObservers()`
50
+ * Requires the background-delivery entitlement (added by the config plugin
51
+ * unless `background: false`). No AppDelegate change is needed; the pod
52
+ * registers the observers on UIApplicationDidFinishLaunchingNotification.
51
53
  */
52
54
  configureBackgroundTypes(
53
55
  typeIdentifiers: string[],
@@ -116,6 +118,25 @@ export interface CoreModule extends HybridObject<{ ios: 'swift' }> {
116
118
  typeIdentifier: PerObjectTypeIdentifier,
117
119
  ): Promise<void>
118
120
 
121
+ /**
122
+ * Reports, for each of the given object types, the earliest date from which the app is
123
+ * authorized to read samples when the user has granted only limited access.
124
+ *
125
+ * A type is only present in the result when the user has imposed a lower time bound on
126
+ * the app's read access for it - types without such a bound are omitted. Use it to clamp
127
+ * the `startDate` of a query filter so you don't request data you can't read.
128
+ *
129
+ * Requires iOS 27. On earlier versions there is no limited-access lower bound, so this
130
+ * resolves to an empty object. It also resolves to an empty object - and logs a warning -
131
+ * when running on iOS 27 in an app built with an SDK older than iOS 27, since the
132
+ * underlying API cannot be called from such a binary.
133
+ *
134
+ * @see {@link https://developer.apple.com/documentation/healthkit/hkhealthstore/earliestauthorizedsampledate(for:) Apple Docs }
135
+ */
136
+ getEarliestAuthorizedSampleDates(
137
+ objectTypeIdentifiers: readonly ObjectTypeIdentifier[],
138
+ ): Promise<Record<string, Date>>
139
+
119
140
  deleteObjects(
120
141
  objectTypeIdentifier: SampleTypeIdentifierWriteable,
121
142
  filter: FilterForSamples,
@@ -1,9 +1,7 @@
1
+ import type { Source } from '@react-native-healthkit/core'
1
2
  import type { HybridObject } from 'react-native-nitro-modules'
2
3
 
3
- interface Source {
4
- readonly name: string
5
- readonly bundleIdentifier: string
6
- }
4
+ export type { Source }
7
5
 
8
6
  /**
9
7
  * @see {@link https://developer.apple.com/documentation/healthkit/hkobject/1615781-source Apple Docs }
package/src/test-setup.ts CHANGED
@@ -50,6 +50,7 @@ const mockModule = {
50
50
  isObjectTypeAvailableAsync: jest.fn(),
51
51
  areObjectTypesAvailable: jest.fn(),
52
52
  areObjectTypesAvailableAsync: jest.fn(),
53
+ getEarliestAuthorizedSampleDates: jest.fn(),
53
54
  queryStateOfMindSamples: jest.fn(),
54
55
  workoutSessionMirroringStartHandler: jest.fn(),
55
56
  }
@@ -7,14 +7,18 @@ import type {
7
7
  CategoryValueSleepAnalysis,
8
8
  CorrelationSampleTyped,
9
9
  HeartRateMotionContext,
10
+ InsulinDeliveryReason,
11
+ MetadataForQuantityIdentifier,
10
12
  Quantity,
11
13
  QuantitySampleTyped,
12
14
  QuantityTypeIdentifier,
15
+ QuantityTypeIdentifierWriteable,
13
16
  QueryOptionsWithAnchorAndUnit,
14
17
  QueryOptionsWithSortOrderAndUnit,
15
18
  StateOfMindSampleTyped,
16
19
  StatisticsQueryOptions,
17
20
  SwimmingStrokeStyle,
21
+ UnitForIdentifier,
18
22
  WorkoutEventTyped,
19
23
  WorkoutSampleTyped,
20
24
  } from '../types'
@@ -26,6 +30,13 @@ type Equal<A, B> =
26
30
 
27
31
  type Assert<T extends true> = T
28
32
 
33
+ // Mirrors saveQuantitySample(identifier, unit, value, start, end, metadata?).
34
+ type AssertSaveQuantitySampleCall<
35
+ T extends QuantityTypeIdentifierWriteable,
36
+ _TUnit extends UnitForIdentifier<T>,
37
+ _TMetadata extends MetadataForQuantityIdentifier<T>,
38
+ > = true
39
+
29
40
  type _sleepAnalysisValuesAreTyped = Assert<
30
41
  Equal<
31
42
  CategoryValueForIdentifier<'HKCategoryTypeIdentifierSleepAnalysis'>,
@@ -39,10 +50,11 @@ type _newCategoryIdentifierFromSdkIsPresent = Assert<
39
50
  : false
40
51
  >
41
52
 
42
- type _bloodKetonesIdentifierIsPresent = Assert<
53
+ // Apple has never shipped a blood ketones quantity type (see issue #379).
54
+ type _bloodKetonesIdentifierIsAbsent = Assert<
43
55
  'HKQuantityTypeIdentifierBloodKetones' extends QuantityTypeIdentifier
44
- ? true
45
- : false
56
+ ? false
57
+ : true
46
58
  >
47
59
 
48
60
  type _heartRateMetadataNarrowsToEnum = Assert<
@@ -87,12 +99,22 @@ type _bloodGlucoseUnitNarrows = Assert<
87
99
  >
88
100
  >
89
101
 
90
- type _bloodKetonesUnitNarrows = Assert<
91
- Equal<
92
- QuantitySampleTyped<'HKQuantityTypeIdentifierBloodKetones'>['unit'],
93
- BloodGlucoseUnit
102
+ type _saveQuantitySampleBodyMassAcceptsAppSpecificMetadata =
103
+ AssertSaveQuantitySampleCall<
104
+ 'HKQuantityTypeIdentifierBodyMass',
105
+ 'kg',
106
+ { APP_CUSTOM_KEY: 'v1'; HKWasUserEntered: true }
107
+ >
108
+
109
+ type _saveQuantitySampleInsulinAcceptsOfficialAndAppSpecificMetadata =
110
+ AssertSaveQuantitySampleCall<
111
+ 'HKQuantityTypeIdentifierInsulinDelivery',
112
+ 'IU',
113
+ {
114
+ HKInsulinDeliveryReason: InsulinDeliveryReason.basal
115
+ APP_CUSTOM_KEY: 'v1'
116
+ }
94
117
  >
95
- >
96
118
 
97
119
  type _quantityQueryOptionsUnitNarrows = Assert<
98
120
  Equal<
package/src/types/Auth.ts CHANGED
@@ -1,17 +1,4 @@
1
- /**
2
- * @see {@link https://developer.apple.com/documentation/healthkit/hkauthorizationrequeststatus Apple Docs }
3
- */
4
- export enum AuthorizationRequestStatus {
5
- unknown = 0,
6
- shouldRequest = 1,
7
- unnecessary = 2,
8
- }
9
-
10
- /**
11
- * @see {@link https://developer.apple.com/documentation/healthkit/hkauthorizationstatus Apple Docs }
12
- */
13
- export enum AuthorizationStatus {
14
- notDetermined = 0,
15
- sharingDenied = 1,
16
- sharingAuthorized = 2,
17
- }
1
+ export {
2
+ AuthorizationRequestStatus,
3
+ AuthorizationStatus,
4
+ } from '@react-native-healthkit/core'
@@ -1,9 +1 @@
1
- /**
2
- * @see {@link https://developer.apple.com/documentation/healthkit/hkupdatefrequency Apple Docs }
3
- */
4
- export enum UpdateFrequency {
5
- immediate = 1,
6
- hourly = 2,
7
- daily = 3,
8
- weekly = 4,
9
- }
1
+ export { UpdateFrequency } from '@react-native-healthkit/core'
@@ -1,13 +1 @@
1
- /**
2
- * @see {@link https://developer.apple.com/documentation/healthkit/hkdevice Apple Docs }
3
- */
4
- export interface Device {
5
- readonly name?: string // ex: "Apple Watch"
6
- readonly firmwareVersion?: string
7
- readonly hardwareVersion?: string // ex: "Watch6,2",
8
- readonly localIdentifier?: string
9
- readonly manufacturer?: string // ex: "Apple Inc."
10
- readonly model?: string // ex: "Watch"
11
- readonly softwareVersion?: string // ex: "9.0"
12
- readonly udiDeviceIdentifier?: string
13
- }
1
+ export type { Device } from '@react-native-healthkit/core'
@@ -3,11 +3,11 @@ import {
3
3
  HeartRateMotionContext,
4
4
  InsulinDeliveryReason,
5
5
  } from '../generated/healthkit.generated'
6
- import type { SourceProxy } from '../specs/SourceProxy.nitro'
7
6
  import type { QuantitySample, QuantitySampleTyped } from './QuantitySample'
8
7
  import type { QuantityTypeIdentifier } from './QuantityTypeIdentifier'
9
8
  import type { FilterForSamples } from './QueryOptions'
10
9
  import type { DeletedSample } from './Shared'
10
+ import type { Source } from './Source'
11
11
 
12
12
  export { HeartRateMotionContext, InsulinDeliveryReason }
13
13
 
@@ -26,12 +26,12 @@ export interface QueryStatisticsResponse {
26
26
  readonly duration?: Quantity
27
27
  readonly startDate?: Date
28
28
  readonly endDate?: Date
29
- sources: SourceProxy[]
29
+ readonly sources: readonly Source[]
30
30
  }
31
31
 
32
32
  export interface QueryStatisticsResponseFromSingleSource
33
33
  extends Omit<QueryStatisticsResponse, 'sources'> {
34
- readonly source: SourceProxy
34
+ readonly source: Source
35
35
  }
36
36
 
37
37
  export enum AggregationStyle {
@@ -1,71 +1,13 @@
1
+ import type {
2
+ DateFilter,
3
+ PredicateWithMetadataKey,
4
+ StrictUnion,
5
+ } from '@react-native-healthkit/core'
1
6
  import type { SourceProxy } from '../specs/SourceProxy.nitro'
2
7
  import type { WorkoutProxy } from '../specs/WorkoutProxy.nitro'
3
8
 
4
- export enum ComparisonPredicateOperator {
5
- lessThan = 0,
6
-
7
- lessThanOrEqualTo = 1,
8
-
9
- greaterThan = 2,
10
-
11
- greaterThanOrEqualTo = 3,
12
-
13
- equalTo = 4,
14
-
15
- notEqualTo = 5,
16
-
17
- matches = 6,
18
-
19
- like = 7,
20
-
21
- beginsWith = 8,
22
-
23
- endsWith = 9,
24
-
25
- IN = 10,
26
-
27
- customSelector = 11,
28
-
29
- contains = 99,
30
-
31
- between = 100,
32
- }
33
-
34
- type PredicateWithMetadataValue = string | number | Date | boolean
35
-
36
- export interface PredicateWithMetadataKey {
37
- readonly withMetadataKey: string
38
- readonly operatorType?: ComparisonPredicateOperator
39
- readonly value?: PredicateWithMetadataValue
40
- }
41
- // Computes and flattens object types
42
- // biome-ignore lint/complexity/noBannedTypes: it works
43
- type ComputeRaw<A> = A extends Function ? A : { [K in keyof A]: A[K] } & {}
44
-
45
- // Gets all keys from a union of objects
46
- // biome-ignore lint/suspicious/noExplicitAny: it works
47
- type AllKeys<U> = U extends any ? keyof U : never
48
-
49
- // The core: for each member U in the union,
50
- // add `?: never` for any key that exists in other union members.
51
- // biome-ignore lint/suspicious/noExplicitAny: it works
52
- type _Strict<U, UAll extends U = U> = U extends any
53
- ? ComputeRaw<
54
- U & {
55
- [K in Exclude<AllKeys<UAll>, keyof U>]?: never
56
- }
57
- >
58
- : never
59
-
60
- // The exported type you can copy into your codebase
61
- export type StrictUnion<U extends object> = _Strict<U>
62
-
63
- export interface DateFilter {
64
- readonly startDate?: Date
65
- readonly endDate?: Date
66
- readonly strictEndDate?: boolean
67
- readonly strictStartDate?: boolean
68
- }
9
+ export { ComparisonPredicateOperator } from '@react-native-healthkit/core'
10
+ export type { DateFilter, PredicateWithMetadataKey, StrictUnion }
69
11
 
70
12
  export interface FilterForSamplesBase {
71
13
  readonly uuid?: string
@@ -1,3 +1,9 @@
1
+ import type {
2
+ BaseObject,
3
+ BaseSample,
4
+ DeletedSample,
5
+ SampleType,
6
+ } from '@react-native-healthkit/core'
1
7
  import type { AnyMap } from 'react-native-nitro-modules'
2
8
  import type {
3
9
  KnownObjectMetadata,
@@ -20,17 +26,12 @@ import type {
20
26
  WorkoutTypeIdentifier,
21
27
  } from './Constants'
22
28
  import type { CorrelationTypeIdentifier } from './CorrelationType'
23
- import type { Device } from './Device'
24
29
  import type {
25
30
  QuantityTypeIdentifier,
26
31
  QuantityTypeIdentifierWriteable,
27
32
  } from './QuantityTypeIdentifier'
28
- import type { SourceRevision } from './Source'
29
33
 
30
- export interface DeletedSample {
31
- readonly uuid: string
32
- readonly metadata?: AnyMap
33
- }
34
+ export type { BaseObject, BaseSample, DeletedSample, SampleType }
34
35
 
35
36
  export type ObjectTypeIdentifier =
36
37
  | CharacteristicTypeIdentifier
@@ -80,25 +81,3 @@ export type BaseObjectTyped<TMetadata extends object = KnownObjectMetadata> =
80
81
  WithTypedMetadata<BaseObject, TMetadata>
81
82
  export type BaseSampleTyped<TMetadata extends object = KnownSampleMetadata> =
82
83
  WithTypedMetadata<BaseSample, TMetadata>
83
-
84
- export interface BaseObject {
85
- readonly uuid: string
86
- readonly sourceRevision: SourceRevision
87
- readonly device?: Device
88
- readonly metadata: AnyMap
89
- }
90
-
91
- export interface SampleType {
92
- identifier: string
93
- allowsRecalibrationForEstimates: boolean
94
- isMinimumDurationRestricted: boolean
95
- isMaximumDurationRestricted: boolean
96
- }
97
-
98
- export interface BaseSample extends BaseObject {
99
- readonly sampleType: SampleType
100
- readonly startDate: Date
101
- readonly endDate: Date
102
- readonly hasUndeterminedDuration: boolean
103
- readonly metadata: AnyMap
104
- }
@@ -1,11 +1 @@
1
- import type { SourceProxy } from '../specs/SourceProxy.nitro'
2
-
3
- /**
4
- * @see {@link https://developer.apple.com/documentation/healthkit/hkobject/1615483-sourcerevision Apple Docs }
5
- */
6
- export interface SourceRevision {
7
- readonly source: SourceProxy
8
- readonly version?: string
9
- readonly operatingSystemVersion: string
10
- readonly productType?: string
11
- }
1
+ export type { Source, SourceRevision } from '@react-native-healthkit/core'
@@ -1,12 +1,11 @@
1
+ import type { EmitterSubscription } from '@react-native-healthkit/core'
1
2
  import type { CategorySampleTyped } from './CategoryType'
2
3
  import type { CategoryTypeIdentifier } from './CategoryTypeIdentifier'
3
4
  import type { QuantitySampleTyped } from './QuantitySample'
4
5
  import type { QuantityTypeIdentifier } from './QuantityTypeIdentifier'
5
6
  import type { SampleTypeIdentifier } from './Shared'
6
7
 
7
- export interface EmitterSubscription {
8
- remove: () => void
9
- }
8
+ export type { EmitterSubscription }
10
9
 
11
10
  export interface OnChangeCallbackArgs {
12
11
  readonly typeIdentifier: SampleTypeIdentifier
@@ -161,7 +161,7 @@ export type UnitOfEnergy = 'kcal' | 'Cal' | 'cal' | 'J'
161
161
 
162
162
  export type EnergyUnit = JouleUnit<MetricPrefix> | UnitOfEnergy
163
163
 
164
- export type BloodGlucoseUnit = 'mmol<180.15588000005408>/l' | 'mmol/L' | 'mg/dL'
164
+ export type BloodGlucoseUnit = 'mmol<180.15588000005408>/l' | 'mg/dL'
165
165
 
166
166
  export type SpeedUnit<
167
167
  TLength extends LengthUnit,