@kafitra/react-native-live-tracking 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (132) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +396 -0
  3. package/android/build.gradle +71 -0
  4. package/android/gradle.properties +7 -0
  5. package/android/src/main/AndroidManifest.xml +40 -0
  6. package/android/src/main/java/com/livetracking/LiveTrackingModuleImpl.kt +728 -0
  7. package/android/src/main/java/com/livetracking/LiveTrackingPackage.kt +16 -0
  8. package/android/src/main/java/com/livetracking/location/LocationEngine.kt +93 -0
  9. package/android/src/main/java/com/livetracking/network/NetworkListener.kt +127 -0
  10. package/android/src/main/java/com/livetracking/optimizer/ActivityRecognitionHandler.kt +248 -0
  11. package/android/src/main/java/com/livetracking/optimizer/MotionSleepManager.kt +130 -0
  12. package/android/src/main/java/com/livetracking/permissions/PermissionHandler.kt +145 -0
  13. package/android/src/main/java/com/livetracking/queue/QueueEngine.kt +167 -0
  14. package/android/src/main/java/com/livetracking/queue/QueuedLocation.kt +16 -0
  15. package/android/src/main/java/com/livetracking/queue/TrackingDatabase.kt +239 -0
  16. package/android/src/main/java/com/livetracking/receiver/BootReceiver.kt +53 -0
  17. package/android/src/main/java/com/livetracking/service/TrackingForegroundService.kt +145 -0
  18. package/android/src/main/java/com/livetracking/sync/FirebaseSyncEngine.kt +277 -0
  19. package/android/src/main/java/com/livetracking/sync/LocationDataPoint.kt +31 -0
  20. package/android/src/main/java/com/livetracking/sync/SyncEngineController.kt +220 -0
  21. package/android/src/main/java/com/livetracking/sync/SyncTargetConfig.kt +20 -0
  22. package/android/src/main/java/com/livetracking/sync/TargetHandler.kt +601 -0
  23. package/android/src/newarch/java/com/livetracking/LiveTrackingModule.kt +64 -0
  24. package/android/src/oldarch/java/com/livetracking/LiveTrackingModule.kt +70 -0
  25. package/android/src/test/java/com/livetracking/BackoffCalculationTest.kt +216 -0
  26. package/android/src/test/java/com/livetracking/BatchAccumulatorTest.kt +391 -0
  27. package/android/src/test/java/com/livetracking/BootReceiverTest.kt +247 -0
  28. package/android/src/test/java/com/livetracking/FirebaseSyncEngineTest.kt +337 -0
  29. package/android/src/test/java/com/livetracking/LocationEngineTest.kt +202 -0
  30. package/android/src/test/java/com/livetracking/MotionSleepManagerTest.kt +420 -0
  31. package/android/src/test/java/com/livetracking/OfflineQueueTest.kt +462 -0
  32. package/android/src/test/java/com/livetracking/PermissionHandlerTest.kt +200 -0
  33. package/android/src/test/java/com/livetracking/QueueEngineTest.kt +335 -0
  34. package/android/src/test/java/com/livetracking/SyncEngineControllerTest.kt +855 -0
  35. package/ios/ActivityRecognitionHandler.swift +196 -0
  36. package/ios/BackgroundModeHelper.swift +132 -0
  37. package/ios/FirebaseSyncEngine.swift +276 -0
  38. package/ios/LiveTracking-Bridging-Header.h +2 -0
  39. package/ios/LiveTracking.m +37 -0
  40. package/ios/LiveTracking.swift +773 -0
  41. package/ios/LocationDataPoint.swift +56 -0
  42. package/ios/LocationEngine.swift +160 -0
  43. package/ios/MotionSleepManager.swift +151 -0
  44. package/ios/NetworkListener.swift +105 -0
  45. package/ios/OfflineQueueManager.swift +503 -0
  46. package/ios/PermissionHandler.swift +148 -0
  47. package/ios/QueueEngine.swift +249 -0
  48. package/ios/SyncEngineController.swift +396 -0
  49. package/ios/SyncTargetConfig.swift +36 -0
  50. package/ios/TargetHandler.swift +715 -0
  51. package/ios/Tests/ActivityRecognitionHandlerTests.swift +259 -0
  52. package/ios/Tests/FirebaseSyncEngineTests.swift +303 -0
  53. package/ios/Tests/LocationEngineTests.swift +244 -0
  54. package/ios/Tests/MotionSleepManagerTests.swift +355 -0
  55. package/ios/Tests/NetworkListenerTests.swift +188 -0
  56. package/ios/Tests/OfflineQueueFlushTests.swift +375 -0
  57. package/ios/Tests/PermissionHandlerTests.swift +238 -0
  58. package/ios/Tests/QueueEngineTests.swift +346 -0
  59. package/ios/TrackingCleanup.swift +93 -0
  60. package/ios/TrackingNotificationManager.swift +187 -0
  61. package/lib/commonjs/EventEmitter.js +113 -0
  62. package/lib/commonjs/EventEmitter.js.map +1 -0
  63. package/lib/commonjs/LiveTracking.js +134 -0
  64. package/lib/commonjs/LiveTracking.js.map +1 -0
  65. package/lib/commonjs/NativeLiveTracking.js +21 -0
  66. package/lib/commonjs/NativeLiveTracking.js.map +1 -0
  67. package/lib/commonjs/filters/distanceTimeFilter.js +63 -0
  68. package/lib/commonjs/filters/distanceTimeFilter.js.map +1 -0
  69. package/lib/commonjs/index.js +103 -0
  70. package/lib/commonjs/index.js.map +1 -0
  71. package/lib/commonjs/serialization/locationSerializer.js +51 -0
  72. package/lib/commonjs/serialization/locationSerializer.js.map +1 -0
  73. package/lib/commonjs/types.js +77 -0
  74. package/lib/commonjs/types.js.map +1 -0
  75. package/lib/commonjs/utils/distance.js +63 -0
  76. package/lib/commonjs/utils/distance.js.map +1 -0
  77. package/lib/commonjs/utils/retry.js +80 -0
  78. package/lib/commonjs/utils/retry.js.map +1 -0
  79. package/lib/commonjs/validation.js +463 -0
  80. package/lib/commonjs/validation.js.map +1 -0
  81. package/lib/module/EventEmitter.js +105 -0
  82. package/lib/module/EventEmitter.js.map +1 -0
  83. package/lib/module/LiveTracking.js +127 -0
  84. package/lib/module/LiveTracking.js.map +1 -0
  85. package/lib/module/NativeLiveTracking.js +16 -0
  86. package/lib/module/NativeLiveTracking.js.map +1 -0
  87. package/lib/module/filters/distanceTimeFilter.js +58 -0
  88. package/lib/module/filters/distanceTimeFilter.js.map +1 -0
  89. package/lib/module/index.js +32 -0
  90. package/lib/module/index.js.map +1 -0
  91. package/lib/module/serialization/locationSerializer.js +45 -0
  92. package/lib/module/serialization/locationSerializer.js.map +1 -0
  93. package/lib/module/types.js +94 -0
  94. package/lib/module/types.js.map +1 -0
  95. package/lib/module/utils/distance.js +56 -0
  96. package/lib/module/utils/distance.js.map +1 -0
  97. package/lib/module/utils/retry.js +72 -0
  98. package/lib/module/utils/retry.js.map +1 -0
  99. package/lib/module/validation.js +456 -0
  100. package/lib/module/validation.js.map +1 -0
  101. package/lib/typescript/EventEmitter.d.ts +65 -0
  102. package/lib/typescript/EventEmitter.d.ts.map +1 -0
  103. package/lib/typescript/LiveTracking.d.ts +23 -0
  104. package/lib/typescript/LiveTracking.d.ts.map +1 -0
  105. package/lib/typescript/NativeLiveTracking.d.ts +25 -0
  106. package/lib/typescript/NativeLiveTracking.d.ts.map +1 -0
  107. package/lib/typescript/filters/distanceTimeFilter.d.ts +44 -0
  108. package/lib/typescript/filters/distanceTimeFilter.d.ts.map +1 -0
  109. package/lib/typescript/index.d.ts +21 -0
  110. package/lib/typescript/index.d.ts.map +1 -0
  111. package/lib/typescript/serialization/locationSerializer.d.ts +39 -0
  112. package/lib/typescript/serialization/locationSerializer.d.ts.map +1 -0
  113. package/lib/typescript/types.d.ts +217 -0
  114. package/lib/typescript/types.d.ts.map +1 -0
  115. package/lib/typescript/utils/distance.d.ts +38 -0
  116. package/lib/typescript/utils/distance.d.ts.map +1 -0
  117. package/lib/typescript/utils/retry.d.ts +60 -0
  118. package/lib/typescript/utils/retry.d.ts.map +1 -0
  119. package/lib/typescript/validation.d.ts +26 -0
  120. package/lib/typescript/validation.d.ts.map +1 -0
  121. package/package.json +126 -0
  122. package/react-native-live-tracking.podspec +47 -0
  123. package/src/EventEmitter.ts +118 -0
  124. package/src/LiveTracking.ts +159 -0
  125. package/src/NativeLiveTracking.ts +29 -0
  126. package/src/filters/distanceTimeFilter.ts +75 -0
  127. package/src/index.ts +51 -0
  128. package/src/serialization/locationSerializer.ts +57 -0
  129. package/src/types.ts +252 -0
  130. package/src/utils/distance.ts +68 -0
  131. package/src/utils/retry.ts +75 -0
  132. package/src/validation.ts +552 -0
@@ -0,0 +1,187 @@
1
+ import Foundation
2
+ import UserNotifications
3
+
4
+ /**
5
+ * Manages persistent local notifications for iOS live tracking.
6
+ *
7
+ * iOS does not have a "foreground service" concept like Android. Instead,
8
+ * this manager posts a local notification when tracking starts and removes it
9
+ * when tracking stops. If the user dismisses the notification, it is re-posted
10
+ * to maintain visibility (similar to Android's foreground service notification).
11
+ *
12
+ * Requirements:
13
+ * - Show persistent notification while tracking is active
14
+ * - Re-post notification if dismissed by user
15
+ * - Remove notification when tracking stops
16
+ * - Gracefully degrade if notification permission is denied
17
+ */
18
+ @objc
19
+ class TrackingNotificationManager: NSObject, UNUserNotificationCenterDelegate {
20
+
21
+ // MARK: - Constants
22
+
23
+ private static let notificationIdentifier = "com.livetracking.persistent"
24
+ private static let categoryIdentifier = "LIVE_TRACKING_CATEGORY"
25
+ private static let recheckInterval: TimeInterval = 5.0
26
+
27
+ // MARK: - Properties
28
+
29
+ private var title: String = "Live Tracking"
30
+ private var body: String = "Tracking your location"
31
+ private var isTrackingActive: Bool = false
32
+ private var recheckTimer: Timer?
33
+ private var hasNotificationPermission: Bool = false
34
+
35
+ // MARK: - Singleton
36
+
37
+ @objc static let shared = TrackingNotificationManager()
38
+
39
+ private override init() {
40
+ super.init()
41
+ setupNotificationCategory()
42
+ }
43
+
44
+ // MARK: - Configuration
45
+
46
+ /**
47
+ * Configure the notification title and body text.
48
+ *
49
+ * - Parameter title: The notification title
50
+ * - Parameter body: The notification body text
51
+ */
52
+ @objc
53
+ func configure(title: String, body: String) {
54
+ self.title = title
55
+ self.body = body
56
+ }
57
+
58
+ // MARK: - Public Methods
59
+
60
+ /**
61
+ * Show the persistent tracking notification.
62
+ * Requests notification permission if not already granted.
63
+ * Starts a re-check timer to re-post if the user dismisses it.
64
+ */
65
+ @objc
66
+ func showTrackingNotification() {
67
+ isTrackingActive = true
68
+
69
+ let center = UNUserNotificationCenter.current()
70
+ center.delegate = self
71
+
72
+ center.requestAuthorization(options: [.alert, .sound]) { [weak self] granted, _ in
73
+ guard let self = self else { return }
74
+ self.hasNotificationPermission = granted
75
+ if granted {
76
+ DispatchQueue.main.async {
77
+ self.postNotification()
78
+ self.startRecheckTimer()
79
+ }
80
+ }
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Remove the tracking notification and stop the re-check timer.
86
+ */
87
+ @objc
88
+ func removeTrackingNotification() {
89
+ isTrackingActive = false
90
+ stopRecheckTimer()
91
+
92
+ let center = UNUserNotificationCenter.current()
93
+ center.removeDeliveredNotifications(withIdentifiers: [TrackingNotificationManager.notificationIdentifier])
94
+ center.removePendingNotificationRequests(withIdentifiers: [TrackingNotificationManager.notificationIdentifier])
95
+ }
96
+
97
+ // MARK: - UNUserNotificationCenterDelegate
98
+
99
+ /**
100
+ * Handle notification presentation while app is in foreground.
101
+ * Show the notification banner even when app is active.
102
+ */
103
+ func userNotificationCenter(
104
+ _ center: UNUserNotificationCenter,
105
+ willPresent notification: UNNotification,
106
+ withCompletionHandler completionHandler: @escaping (UNNotificationPresentationOptions) -> Void
107
+ ) {
108
+ if notification.request.identifier == TrackingNotificationManager.notificationIdentifier {
109
+ completionHandler([.banner])
110
+ } else {
111
+ completionHandler([.banner, .sound])
112
+ }
113
+ }
114
+
115
+ // MARK: - Private Methods
116
+
117
+ private func setupNotificationCategory() {
118
+ let category = UNNotificationCategory(
119
+ identifier: TrackingNotificationManager.categoryIdentifier,
120
+ actions: [],
121
+ intentIdentifiers: [],
122
+ options: []
123
+ )
124
+ UNUserNotificationCenter.current().setNotificationCategories([category])
125
+ }
126
+
127
+ private func postNotification() {
128
+ let content = UNMutableNotificationContent()
129
+ content.title = title
130
+ content.body = body
131
+ content.categoryIdentifier = TrackingNotificationManager.categoryIdentifier
132
+ // No sound for persistent notification to avoid annoyance
133
+ content.sound = nil
134
+
135
+ let request = UNNotificationRequest(
136
+ identifier: TrackingNotificationManager.notificationIdentifier,
137
+ content: content,
138
+ trigger: nil // Deliver immediately
139
+ )
140
+
141
+ UNUserNotificationCenter.current().add(request) { error in
142
+ if let error = error {
143
+ print("[TrackingNotificationManager] Failed to post notification: \(error.localizedDescription)")
144
+ }
145
+ }
146
+ }
147
+
148
+ /**
149
+ * Start a timer that periodically checks if the notification is still delivered.
150
+ * If not (user dismissed it), re-post it while tracking is active.
151
+ */
152
+ private func startRecheckTimer() {
153
+ stopRecheckTimer()
154
+ recheckTimer = Timer.scheduledTimer(
155
+ withTimeInterval: TrackingNotificationManager.recheckInterval,
156
+ repeats: true
157
+ ) { [weak self] _ in
158
+ self?.recheckNotification()
159
+ }
160
+ }
161
+
162
+ private func stopRecheckTimer() {
163
+ recheckTimer?.invalidate()
164
+ recheckTimer = nil
165
+ }
166
+
167
+ private func recheckNotification() {
168
+ guard isTrackingActive, hasNotificationPermission else {
169
+ stopRecheckTimer()
170
+ return
171
+ }
172
+
173
+ UNUserNotificationCenter.current().getDeliveredNotifications { [weak self] notifications in
174
+ guard let self = self, self.isTrackingActive else { return }
175
+
176
+ let hasTrackingNotification = notifications.contains {
177
+ $0.request.identifier == TrackingNotificationManager.notificationIdentifier
178
+ }
179
+
180
+ if !hasTrackingNotification {
181
+ DispatchQueue.main.async {
182
+ self.postNotification()
183
+ }
184
+ }
185
+ }
186
+ }
187
+ }
@@ -0,0 +1,113 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.onError = onError;
7
+ exports.onLocationUpdate = onLocationUpdate;
8
+ exports.removeAllListeners = removeAllListeners;
9
+ var _reactNative = require("react-native");
10
+ /**
11
+ * Event listener system for react-native-live-tracking.
12
+ *
13
+ * Wraps NativeEventEmitter to provide typed event subscriptions
14
+ * for location updates and tracking errors.
15
+ *
16
+ * @packageDocumentation
17
+ */
18
+
19
+ /**
20
+ * Directly use the global device event emitter.
21
+ *
22
+ * NativeEventEmitter's constructor accesses Platform.OS, which requires the
23
+ * PlatformConstants native module. In a broken or partially-initialised binary
24
+ * that module can be missing and crash the app before we can even report that
25
+ * LiveTracking is unavailable. DeviceEventEmitter avoids that dependency
26
+ * entirely while still delivering native events emitted by the LiveTracking
27
+ * RCTEventEmitter.
28
+ */
29
+
30
+ /**
31
+ * Register a callback for location updates.
32
+ *
33
+ * The callback is invoked each time a valid location update is emitted
34
+ * from the native layer after passing the Distance/Time Matrix filter.
35
+ *
36
+ * @param callback - Function called with LocationData on each update
37
+ * @returns Subscription with `remove()` method to unsubscribe
38
+ *
39
+ * @example
40
+ * ```ts
41
+ * const subscription = onLocationUpdate((location) => {
42
+ * console.log(location.latitude, location.longitude);
43
+ * });
44
+ * // Later: unsubscribe
45
+ * subscription.remove();
46
+ * ```
47
+ */
48
+ function onLocationUpdate(callback) {
49
+ const nativeSubscription = _reactNative.DeviceEventEmitter.addListener('onLocationUpdate', event => {
50
+ const location = {
51
+ latitude: event.latitude,
52
+ longitude: event.longitude,
53
+ timestamp: event.timestamp,
54
+ accuracy: event.accuracy,
55
+ speed: event.speed ?? null,
56
+ altitude: event.altitude ?? null,
57
+ bearing: event.bearing ?? null
58
+ };
59
+ callback(location);
60
+ });
61
+ return {
62
+ remove: () => {
63
+ nativeSubscription.remove();
64
+ }
65
+ };
66
+ }
67
+
68
+ /**
69
+ * Register a callback for tracking errors.
70
+ *
71
+ * The callback is invoked when an error occurs during tracking
72
+ * (e.g., permission denied, GPS disabled, Firebase write failure).
73
+ *
74
+ * @param callback - Function called with TrackingError on each error event
75
+ * @returns Subscription with `remove()` method to unsubscribe
76
+ *
77
+ * @example
78
+ * ```ts
79
+ * const subscription = onError((error) => {
80
+ * console.error(`[${error.code}] ${error.message}`);
81
+ * });
82
+ * // Later: unsubscribe
83
+ * subscription.remove();
84
+ * ```
85
+ */
86
+ function onError(callback) {
87
+ const nativeSubscription = _reactNative.DeviceEventEmitter.addListener('onTrackingError', event => {
88
+ const error = {
89
+ code: event.code,
90
+ message: event.message,
91
+ recoverable: event.recoverable ?? true,
92
+ details: event.details ?? undefined
93
+ };
94
+ callback(error);
95
+ });
96
+ return {
97
+ remove: () => {
98
+ nativeSubscription.remove();
99
+ }
100
+ };
101
+ }
102
+
103
+ /**
104
+ * Remove all event listeners registered through this module.
105
+ *
106
+ * Useful for cleanup when the tracking module is being torn down
107
+ * or when all subscriptions need to be cleared at once.
108
+ */
109
+ function removeAllListeners() {
110
+ _reactNative.DeviceEventEmitter.removeAllListeners('onLocationUpdate');
111
+ _reactNative.DeviceEventEmitter.removeAllListeners('onTrackingError');
112
+ }
113
+ //# sourceMappingURL=EventEmitter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNative","require","onLocationUpdate","callback","nativeSubscription","DeviceEventEmitter","addListener","event","location","latitude","longitude","timestamp","accuracy","speed","altitude","bearing","remove","onError","error","code","message","recoverable","details","undefined","removeAllListeners"],"sourceRoot":"../../src","sources":["EventEmitter.ts"],"mappings":";;;;;;;;AASA,IAAAA,YAAA,GAAAC,OAAA;AATA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAKA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,gBAAgBA,CAC9BC,QAA0C,EAC5B;EACd,MAAMC,kBAAkB,GAAGC,+BAAkB,CAACC,WAAW,CACvD,kBAAkB,EACjBC,KAA8B,IAAK;IAClC,MAAMC,QAAsB,GAAG;MAC7BC,QAAQ,EAAEF,KAAK,CAACE,QAAkB;MAClCC,SAAS,EAAEH,KAAK,CAACG,SAAmB;MACpCC,SAAS,EAAEJ,KAAK,CAACI,SAAmB;MACpCC,QAAQ,EAAEL,KAAK,CAACK,QAAkB;MAClCC,KAAK,EAAGN,KAAK,CAACM,KAAK,IAAsB,IAAI;MAC7CC,QAAQ,EAAGP,KAAK,CAACO,QAAQ,IAAsB,IAAI;MACnDC,OAAO,EAAGR,KAAK,CAACQ,OAAO,IAAsB;IAC/C,CAAC;IACDZ,QAAQ,CAACK,QAAQ,CAAC;EACpB,CACF,CAAC;EAED,OAAO;IACLQ,MAAM,EAAEA,CAAA,KAAM;MACZZ,kBAAkB,CAACY,MAAM,CAAC,CAAC;IAC7B;EACF,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,OAAOA,CACrBd,QAAwC,EAC1B;EACd,MAAMC,kBAAkB,GAAGC,+BAAkB,CAACC,WAAW,CACvD,iBAAiB,EAChBC,KAA8B,IAAK;IAClC,MAAMW,KAAoB,GAAG;MAC3BC,IAAI,EAAEZ,KAAK,CAACY,IAAc;MAC1BC,OAAO,EAAEb,KAAK,CAACa,OAAiB;MAChCC,WAAW,EAAGd,KAAK,CAACc,WAAW,IAAgB,IAAI;MACnDC,OAAO,EAAGf,KAAK,CAACe,OAAO,IAAgCC;IACzD,CAAC;IACDpB,QAAQ,CAACe,KAAK,CAAC;EACjB,CACF,CAAC;EAED,OAAO;IACLF,MAAM,EAAEA,CAAA,KAAM;MACZZ,kBAAkB,CAACY,MAAM,CAAC,CAAC;IAC7B;EACF,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA;AACA;AACO,SAASQ,kBAAkBA,CAAA,EAAS;EACzCnB,+BAAkB,CAACmB,kBAAkB,CAAC,kBAAkB,CAAC;EACzDnB,+BAAkB,CAACmB,kBAAkB,CAAC,iBAAiB,CAAC;AAC1D","ignoreList":[]}
@@ -0,0 +1,134 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports._resetConfiguredStateForTesting = _resetConfiguredStateForTesting;
7
+ exports.default = void 0;
8
+ var _NativeLiveTracking = _interopRequireDefault(require("./NativeLiveTracking"));
9
+ var _EventEmitter = require("./EventEmitter");
10
+ var _validation = require("./validation");
11
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
12
+ /**
13
+ * JavaScript LiveTracking module that wraps NativeModule calls.
14
+ *
15
+ * Provides the public API for configuring, starting, and stopping
16
+ * location tracking, with validation and state management.
17
+ *
18
+ * @packageDocumentation
19
+ */
20
+
21
+ /**
22
+ * Returns the native module or throws a descriptive error if not linked.
23
+ * Using a function accessor (rather than assertNative) keeps TypeScript
24
+ * happy since it can't narrow an imported binding via assertion functions.
25
+ */
26
+ function native() {
27
+ if (!_NativeLiveTracking.default) {
28
+ throw new Error("[@kafitra/react-native-live-tracking] Native module 'LiveTracking' is not registered. " + 'Make sure you ran `pod install` and rebuilt the app from Xcode.');
29
+ }
30
+ return _NativeLiveTracking.default;
31
+ }
32
+
33
+ /**
34
+ * Tracks whether configure() has been successfully called.
35
+ * Used to guard queue methods that require configuration.
36
+ */
37
+ let isConfigured = false;
38
+
39
+ /**
40
+ * Resets the configured state. Only for use in tests.
41
+ * @internal
42
+ */
43
+ function _resetConfiguredStateForTesting() {
44
+ isConfigured = false;
45
+ }
46
+
47
+ /**
48
+ * LiveTracking module implementation.
49
+ *
50
+ * Wraps native module calls with validation, serialization,
51
+ * and state management on the JavaScript side.
52
+ */
53
+ const LiveTracking = {
54
+ /**
55
+ * Configure the tracking library with the given parameters.
56
+ * Validates the config, applies defaults, and passes to native layer.
57
+ */
58
+ async configure(config) {
59
+ const validationResult = (0, _validation.validateConfig)(config);
60
+ if (!validationResult.valid) {
61
+ const errorMessages = validationResult.errors.map(e => `[${e.field}]: ${e.message}`).join('; ');
62
+ throw new Error(`Invalid configuration: ${errorMessages}`);
63
+ }
64
+ const finalConfig = (0, _validation.applyDefaults)(config);
65
+ const jsonString = JSON.stringify(finalConfig);
66
+ const MAX_PAYLOAD_BYTES = 1024 * 1024; // 1 MB
67
+ if (jsonString.length > MAX_PAYLOAD_BYTES) {
68
+ throw new Error('Configuration payload is too large: serialized JSON exceeds 1 MB');
69
+ }
70
+ await native().configure(jsonString);
71
+ isConfigured = true;
72
+ },
73
+ /**
74
+ * Start location tracking.
75
+ * Requires `configure()` to have been called first.
76
+ */
77
+ async start() {
78
+ await native().start();
79
+ },
80
+ /**
81
+ * Stop location tracking and clean up resources.
82
+ */
83
+ async stop() {
84
+ await native().stop();
85
+ },
86
+ /**
87
+ * Register a callback for location updates.
88
+ */
89
+ onLocationUpdate(callback) {
90
+ return (0, _EventEmitter.onLocationUpdate)(callback);
91
+ },
92
+ /**
93
+ * Register a callback for tracking errors.
94
+ */
95
+ onError(callback) {
96
+ return (0, _EventEmitter.onError)(callback);
97
+ },
98
+ /**
99
+ * Get the current tracking status.
100
+ */
101
+ async getStatus() {
102
+ const jsonString = await native().getStatus();
103
+ return JSON.parse(jsonString);
104
+ },
105
+ /**
106
+ * Get the total number of locations currently queued for sync.
107
+ *
108
+ * @throws Error with code NOT_CONFIGURED if called before configure()
109
+ */
110
+ async getQueuedLocations() {
111
+ if (!isConfigured) {
112
+ const error = new Error('LiveTracking is not configured. Call configure() before getQueuedLocations().');
113
+ error.code = 'NOT_CONFIGURED';
114
+ throw error;
115
+ }
116
+ return native().getQueuedLocations();
117
+ },
118
+ /**
119
+ * Get the number of queued locations per target path.
120
+ *
121
+ * @throws Error with code NOT_CONFIGURED if called before configure()
122
+ */
123
+ async getQueuedLocationsByTarget() {
124
+ if (!isConfigured) {
125
+ const error = new Error('LiveTracking is not configured. Call configure() before getQueuedLocationsByTarget().');
126
+ error.code = 'NOT_CONFIGURED';
127
+ throw error;
128
+ }
129
+ const jsonString = await native().getQueuedLocationsByTarget();
130
+ return JSON.parse(jsonString);
131
+ }
132
+ };
133
+ var _default = exports.default = LiveTracking;
134
+ //# sourceMappingURL=LiveTracking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_NativeLiveTracking","_interopRequireDefault","require","_EventEmitter","_validation","e","__esModule","default","native","NativeLiveTracking","Error","isConfigured","_resetConfiguredStateForTesting","LiveTracking","configure","config","validationResult","validateConfig","valid","errorMessages","errors","map","field","message","join","finalConfig","applyDefaults","jsonString","JSON","stringify","MAX_PAYLOAD_BYTES","length","start","stop","onLocationUpdate","callback","emitterOnLocationUpdate","onError","emitterOnError","getStatus","parse","getQueuedLocations","error","code","getQueuedLocationsByTarget","_default","exports"],"sourceRoot":"../../src","sources":["LiveTracking.ts"],"mappings":"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","ignoreList":[]}
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.default = void 0;
7
+ var _reactNative = require("react-native");
8
+ /**
9
+ * Codegen spec for react-native-live-tracking.
10
+ *
11
+ * Uses TurboModuleRegistry.get (not getEnforcing) so that a missing or
12
+ * not-yet-registered module returns null instead of throwing synchronously.
13
+ * A top-level throw would corrupt the module graph and leave upstream
14
+ * importers (TrackingProvider, AppNavigator) with undefined module records.
15
+ *
16
+ * File must be named Native*.ts and live in the codegenConfig.jsSrcsDir
17
+ * for RN's codegen to pick it up.
18
+ */
19
+ // Try TurboModule first (new arch with codegen), fall back to Bridge (old arch / interop)
20
+ var _default = exports.default = _reactNative.TurboModuleRegistry.get('LiveTracking') ?? _reactNative.NativeModules.LiveTracking;
21
+ //# sourceMappingURL=NativeLiveTracking.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_reactNative","require","_default","exports","default","TurboModuleRegistry","get","NativeModules","LiveTracking"],"sourceRoot":"../../src","sources":["NativeLiveTracking.ts"],"mappings":";;;;;;AAaA,IAAAA,YAAA,GAAAC,OAAA;AAbA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAgBA;AAAA,IAAAC,QAAA,GAAAC,OAAA,CAAAC,OAAA,GACgBC,gCAAmB,CAACC,GAAG,CAAO,cAAc,CAAC,IAC3DC,0BAAa,CAACC,YAAY","ignoreList":[]}
@@ -0,0 +1,63 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ exports.shouldAcceptLocation = shouldAcceptLocation;
7
+ var _distance = require("../utils/distance");
8
+ /**
9
+ * Distance/Time Matrix filter for location updates.
10
+ *
11
+ * This filter implements the battery optimization strategy that accepts a new
12
+ * location update based on the selected mode:
13
+ * - 'both' (default): BOTH time and distance conditions must be met
14
+ * - 'interval': only the time condition must be met
15
+ * - 'distance': only the distance condition must be met
16
+ *
17
+ * @packageDocumentation
18
+ */
19
+
20
+ /**
21
+ * Configuration subset required by the distance/time filter.
22
+ */
23
+
24
+ /**
25
+ * Determines whether a new location should be accepted based on the
26
+ * Distance/Time Matrix filter criteria.
27
+ *
28
+ * The filtering strategy depends on `config.mode`:
29
+ * - 'both': accepted only if both time and distance conditions are met
30
+ * - 'interval': accepted only if enough time has elapsed
31
+ * - 'distance': accepted only if enough distance has been covered
32
+ *
33
+ * @param lastLocation - The most recently accepted location
34
+ * @param newLocation - The candidate location to evaluate
35
+ * @param config - Filter configuration with intervalMs, distanceFilterMeters, and mode
36
+ * @returns `true` if the new location should be accepted, `false` otherwise
37
+ *
38
+ * @example
39
+ * ```typescript
40
+ * const accepted = shouldAcceptLocation(
41
+ * { latitude: -6.2088, longitude: 106.8456, timestamp: 1700000000000, accuracy: 5, speed: null, altitude: null, bearing: null },
42
+ * { latitude: -6.2090, longitude: 106.8460, timestamp: 1700000015000, accuracy: 5, speed: 1.2, altitude: null, bearing: null },
43
+ * { intervalMs: 10000, distanceFilterMeters: 10, mode: 'both' }
44
+ * );
45
+ * ```
46
+ */
47
+ function shouldAcceptLocation(lastLocation, newLocation, config) {
48
+ const mode = config.mode ?? 'both';
49
+ const timeDiff = newLocation.timestamp - lastLocation.timestamp;
50
+ const distance = (0, _distance.calculateDistance)(lastLocation.latitude, lastLocation.longitude, newLocation.latitude, newLocation.longitude);
51
+ const timeMet = timeDiff >= config.intervalMs;
52
+ const distanceMet = distance >= config.distanceFilterMeters;
53
+ switch (mode) {
54
+ case 'interval':
55
+ return timeMet;
56
+ case 'distance':
57
+ return distanceMet;
58
+ case 'both':
59
+ default:
60
+ return timeMet && distanceMet;
61
+ }
62
+ }
63
+ //# sourceMappingURL=distanceTimeFilter.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_distance","require","shouldAcceptLocation","lastLocation","newLocation","config","mode","timeDiff","timestamp","distance","calculateDistance","latitude","longitude","timeMet","intervalMs","distanceMet","distanceFilterMeters"],"sourceRoot":"../../../src","sources":["filters/distanceTimeFilter.ts"],"mappings":";;;;;;AAYA,IAAAA,SAAA,GAAAC,OAAA;AAZA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAKA;AACA;AACA;;AAQA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACO,SAASC,oBAAoBA,CAClCC,YAA0B,EAC1BC,WAAyB,EACzBC,MAAgC,EACvB;EACT,MAAMC,IAAI,GAAGD,MAAM,CAACC,IAAI,IAAI,MAAM;EAClC,MAAMC,QAAQ,GAAGH,WAAW,CAACI,SAAS,GAAGL,YAAY,CAACK,SAAS;EAC/D,MAAMC,QAAQ,GAAG,IAAAC,2BAAiB,EAChCP,YAAY,CAACQ,QAAQ,EACrBR,YAAY,CAACS,SAAS,EACtBR,WAAW,CAACO,QAAQ,EACpBP,WAAW,CAACQ,SACd,CAAC;EAED,MAAMC,OAAO,GAAGN,QAAQ,IAAIF,MAAM,CAACS,UAAU;EAC7C,MAAMC,WAAW,GAAGN,QAAQ,IAAIJ,MAAM,CAACW,oBAAoB;EAE3D,QAAQV,IAAI;IACV,KAAK,UAAU;MACb,OAAOO,OAAO;IAChB,KAAK,UAAU;MACb,OAAOE,WAAW;IACpB,KAAK,MAAM;IACX;MACE,OAAOF,OAAO,IAAIE,WAAW;EACjC;AACF","ignoreList":[]}
@@ -0,0 +1,103 @@
1
+ "use strict";
2
+
3
+ Object.defineProperty(exports, "__esModule", {
4
+ value: true
5
+ });
6
+ Object.defineProperty(exports, "LiveTracking", {
7
+ enumerable: true,
8
+ get: function () {
9
+ return _LiveTracking.default;
10
+ }
11
+ });
12
+ Object.defineProperty(exports, "TrackingState", {
13
+ enumerable: true,
14
+ get: function () {
15
+ return _types.TrackingState;
16
+ }
17
+ });
18
+ Object.defineProperty(exports, "applyDefaults", {
19
+ enumerable: true,
20
+ get: function () {
21
+ return _validation.applyDefaults;
22
+ }
23
+ });
24
+ Object.defineProperty(exports, "calculateBackoffDelay", {
25
+ enumerable: true,
26
+ get: function () {
27
+ return _retry.calculateBackoffDelay;
28
+ }
29
+ });
30
+ Object.defineProperty(exports, "calculateDistance", {
31
+ enumerable: true,
32
+ get: function () {
33
+ return _distance.calculateDistance;
34
+ }
35
+ });
36
+ exports.default = void 0;
37
+ Object.defineProperty(exports, "onError", {
38
+ enumerable: true,
39
+ get: function () {
40
+ return _EventEmitter.onError;
41
+ }
42
+ });
43
+ Object.defineProperty(exports, "onLocationUpdate", {
44
+ enumerable: true,
45
+ get: function () {
46
+ return _EventEmitter.onLocationUpdate;
47
+ }
48
+ });
49
+ Object.defineProperty(exports, "removeAllListeners", {
50
+ enumerable: true,
51
+ get: function () {
52
+ return _EventEmitter.removeAllListeners;
53
+ }
54
+ });
55
+ Object.defineProperty(exports, "serializeLocationForTarget", {
56
+ enumerable: true,
57
+ get: function () {
58
+ return _locationSerializer.serializeLocationForTarget;
59
+ }
60
+ });
61
+ Object.defineProperty(exports, "shouldAcceptLocation", {
62
+ enumerable: true,
63
+ get: function () {
64
+ return _distanceTimeFilter.shouldAcceptLocation;
65
+ }
66
+ });
67
+ Object.defineProperty(exports, "shouldRetry", {
68
+ enumerable: true,
69
+ get: function () {
70
+ return _retry.shouldRetry;
71
+ }
72
+ });
73
+ Object.defineProperty(exports, "validateConfig", {
74
+ enumerable: true,
75
+ get: function () {
76
+ return _validation.validateConfig;
77
+ }
78
+ });
79
+ var _LiveTracking = _interopRequireDefault(require("./LiveTracking"));
80
+ var _types = require("./types");
81
+ var _EventEmitter = require("./EventEmitter");
82
+ var _validation = require("./validation");
83
+ var _distance = require("./utils/distance");
84
+ var _distanceTimeFilter = require("./filters/distanceTimeFilter");
85
+ var _locationSerializer = require("./serialization/locationSerializer");
86
+ var _retry = require("./utils/retry");
87
+ function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
88
+ /**
89
+ * react-native-live-tracking
90
+ *
91
+ * Real-time location tracking library for React Native with Firebase synchronization.
92
+ * Supports both TurboModules (new architecture) and Bridge (old architecture).
93
+ *
94
+ * @packageDocumentation
95
+ */
96
+ var _default = exports.default = _LiveTracking.default; // Re-export all types
97
+ // Event listener functions
98
+ // Configuration validation utilities
99
+ // Distance calculation utility
100
+ // Distance/Time Matrix filter
101
+ // Location serialization for Firebase
102
+ // Retry/backoff utilities
103
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"names":["_LiveTracking","_interopRequireDefault","require","_types","_EventEmitter","_validation","_distance","_distanceTimeFilter","_locationSerializer","_retry","e","__esModule","default","_default","exports","LiveTracking"],"sourceRoot":"../../src","sources":["index.ts"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AASA,IAAAA,aAAA,GAAAC,sBAAA,CAAAC,OAAA;AAMA,IAAAC,MAAA,GAAAD,OAAA;AAmBA,IAAAE,aAAA,GAAAF,OAAA;AAGA,IAAAG,WAAA,GAAAH,OAAA;AAGA,IAAAI,SAAA,GAAAJ,OAAA;AAGA,IAAAK,mBAAA,GAAAL,OAAA;AAGA,IAAAM,mBAAA,GAAAN,OAAA;AAIA,IAAAO,MAAA,GAAAP,OAAA;AAAmE,SAAAD,uBAAAS,CAAA,WAAAA,CAAA,IAAAA,CAAA,CAAAC,UAAA,GAAAD,CAAA,KAAAE,OAAA,EAAAF,CAAA;AAlDnE;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AAPA,IAAAG,QAAA,GAAAC,OAAA,CAAAF,OAAA,GAWeG,qBAAY,EAG3B;AAmBA;AAGA;AAGA;AAGA;AAGA;AAIA","ignoreList":[]}