@wayq/beekon-rn 0.0.1 → 0.0.5

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 (92) hide show
  1. package/BeekonRn.podspec +4 -4
  2. package/README.md +94 -48
  3. package/android/build.gradle +11 -6
  4. package/android/src/main/java/in/wayq/beekonrn/BeekonRnModule.kt +428 -0
  5. package/android/src/main/java/{com → in}/wayq/beekonrn/BeekonRnPackage.kt +1 -1
  6. package/ios/BeekonRn.h +5 -1
  7. package/ios/BeekonRn.mm +90 -34
  8. package/ios/BeekonRn.swift +396 -116
  9. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/BeekonKit +0 -0
  10. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Info.plist +0 -0
  11. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.abi.json +8636 -0
  12. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  13. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.swiftinterface +236 -0
  14. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/PrivacyInfo.xcprivacy +1 -1
  15. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/BeekonKit +0 -0
  16. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Info.plist +0 -0
  17. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.abi.json +8636 -0
  18. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  19. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.swiftinterface +236 -0
  20. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.abi.json +8636 -0
  21. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  22. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +236 -0
  23. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/PrivacyInfo.xcprivacy +1 -1
  24. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/_CodeSignature/CodeResources +2 -14
  25. package/lib/module/NativeBeekonRn.js +22 -7
  26. package/lib/module/NativeBeekonRn.js.map +1 -1
  27. package/lib/module/beekon.js +209 -60
  28. package/lib/module/beekon.js.map +1 -1
  29. package/lib/module/index.js +1 -0
  30. package/lib/module/index.js.map +1 -1
  31. package/lib/module/internal/mappers.js +145 -23
  32. package/lib/module/internal/mappers.js.map +1 -1
  33. package/lib/module/types/enums.js +2 -0
  34. package/lib/module/types/{preset.js.map → enums.js.map} +1 -1
  35. package/lib/module/types/error.js +25 -0
  36. package/lib/module/types/error.js.map +1 -0
  37. package/lib/module/types/geofence.js +2 -0
  38. package/lib/module/types/{position.js.map → geofence.js.map} +1 -1
  39. package/lib/module/types/location.js +4 -0
  40. package/lib/module/types/location.js.map +1 -0
  41. package/lib/module/types/sync.js +2 -0
  42. package/lib/module/types/sync.js.map +1 -0
  43. package/lib/typescript/src/NativeBeekonRn.d.ts +113 -35
  44. package/lib/typescript/src/NativeBeekonRn.d.ts.map +1 -1
  45. package/lib/typescript/src/beekon.d.ts +84 -49
  46. package/lib/typescript/src/beekon.d.ts.map +1 -1
  47. package/lib/typescript/src/index.d.ts +7 -4
  48. package/lib/typescript/src/index.d.ts.map +1 -1
  49. package/lib/typescript/src/internal/mappers.d.ts +16 -3
  50. package/lib/typescript/src/internal/mappers.d.ts.map +1 -1
  51. package/lib/typescript/src/types/config.d.ts +53 -31
  52. package/lib/typescript/src/types/config.d.ts.map +1 -1
  53. package/lib/typescript/src/types/enums.d.ts +48 -0
  54. package/lib/typescript/src/types/enums.d.ts.map +1 -0
  55. package/lib/typescript/src/types/error.d.ts +20 -0
  56. package/lib/typescript/src/types/error.d.ts.map +1 -0
  57. package/lib/typescript/src/types/geofence.d.ts +36 -0
  58. package/lib/typescript/src/types/geofence.d.ts.map +1 -0
  59. package/lib/typescript/src/types/location.d.ts +40 -0
  60. package/lib/typescript/src/types/location.d.ts.map +1 -0
  61. package/lib/typescript/src/types/state.d.ts +18 -9
  62. package/lib/typescript/src/types/state.d.ts.map +1 -1
  63. package/lib/typescript/src/types/sync.d.ts +27 -0
  64. package/lib/typescript/src/types/sync.d.ts.map +1 -0
  65. package/package.json +5 -6
  66. package/scripts/fetch-beekonkit.sh +5 -2
  67. package/src/NativeBeekonRn.ts +120 -34
  68. package/src/beekon.ts +235 -63
  69. package/src/index.tsx +23 -4
  70. package/src/internal/mappers.ts +213 -22
  71. package/src/types/config.ts +54 -31
  72. package/src/types/enums.ts +64 -0
  73. package/src/types/error.ts +25 -0
  74. package/src/types/geofence.ts +37 -0
  75. package/src/types/location.ts +45 -0
  76. package/src/types/state.ts +23 -7
  77. package/src/types/sync.ts +23 -0
  78. package/android/src/main/java/com/wayq/beekonrn/BeekonRnModule.kt +0 -233
  79. package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeDirectory +0 -0
  80. package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeRequirements +0 -0
  81. package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeRequirements-1 +0 -0
  82. package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeResources +0 -233
  83. package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeSignature +0 -0
  84. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/_CodeSignature/CodeResources +0 -113
  85. package/lib/module/types/position.js +0 -2
  86. package/lib/module/types/preset.js +0 -2
  87. package/lib/typescript/src/types/position.d.ts +0 -24
  88. package/lib/typescript/src/types/position.d.ts.map +0 -1
  89. package/lib/typescript/src/types/preset.d.ts +0 -12
  90. package/lib/typescript/src/types/preset.d.ts.map +0 -1
  91. package/src/types/position.ts +0 -23
  92. package/src/types/preset.ts +0 -11
@@ -0,0 +1,428 @@
1
+ package `in`.wayq.beekonrn
2
+
3
+ import com.facebook.react.bridge.Arguments
4
+ import com.facebook.react.bridge.Promise
5
+ import com.facebook.react.bridge.ReactApplicationContext
6
+ import com.facebook.react.bridge.ReadableArray
7
+ import com.facebook.react.bridge.ReadableMap
8
+ import com.facebook.react.bridge.WritableArray
9
+ import com.facebook.react.bridge.WritableMap
10
+ import `in`.wayq.beekon.AccuracyMode
11
+ import `in`.wayq.beekon.ActivityType
12
+ import `in`.wayq.beekon.Beekon
13
+ import `in`.wayq.beekon.BeekonConfig
14
+ import `in`.wayq.beekon.BeekonException
15
+ import `in`.wayq.beekon.BeekonGeofence
16
+ import `in`.wayq.beekon.BeekonState
17
+ import `in`.wayq.beekon.GeofenceEvent
18
+ import `in`.wayq.beekon.Location
19
+ import `in`.wayq.beekon.LocationQuality
20
+ import `in`.wayq.beekon.LocationTrigger
21
+ import `in`.wayq.beekon.MotionState
22
+ import `in`.wayq.beekon.NotificationConfig
23
+ import `in`.wayq.beekon.StationaryMode
24
+ import `in`.wayq.beekon.StopReason
25
+ import `in`.wayq.beekon.SyncConfig
26
+ import `in`.wayq.beekon.SyncFailure
27
+ import `in`.wayq.beekon.SyncStatus
28
+ import `in`.wayq.beekon.Transition
29
+ import java.time.Instant
30
+ import kotlinx.coroutines.CoroutineScope
31
+ import kotlinx.coroutines.Dispatchers
32
+ import kotlinx.coroutines.SupervisorJob
33
+ import kotlinx.coroutines.cancel
34
+ import kotlinx.coroutines.launch
35
+
36
+ class BeekonRnModule(reactContext: ReactApplicationContext) :
37
+ NativeBeekonRnSpec(reactContext) {
38
+
39
+ // Default dispatcher (not Main.immediate) — Codegen's emitOnX is thread-safe
40
+ // and marshals to JS internally, so collecting on Main buys nothing and risks
41
+ // jank if a mapper does work. SupervisorJob so one failing collector doesn't
42
+ // tear down its siblings.
43
+ private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
44
+
45
+ init {
46
+ // No Beekon.initialize() — the SDK auto-initializes via AndroidX Startup.
47
+ scope.launch { Beekon.state.collect { emitOnState(stateToWire(it)) } }
48
+ scope.launch { Beekon.locations.collect { emitOnLocation(locationToWire(it)) } }
49
+ scope.launch {
50
+ Beekon.geofenceEvents.collect { emitOnGeofenceEvent(geofenceEventToWire(it)) }
51
+ }
52
+ scope.launch { Beekon.syncStatus.collect { emitOnSyncStatus(syncStatusToWire(it)) } }
53
+ }
54
+
55
+ // ---------------------------------------------------------------------------
56
+ // Lifecycle (non-suspend native calls resolve directly)
57
+ // ---------------------------------------------------------------------------
58
+
59
+ override fun configure(config: ReadableMap, promise: Promise) {
60
+ try {
61
+ Beekon.configure(wireToConfig(config))
62
+ promise.resolve(null)
63
+ } catch (t: Throwable) {
64
+ promise.reject(errorCode(t), t.message ?: "configure failed", t)
65
+ }
66
+ }
67
+
68
+ override fun start(promise: Promise) {
69
+ scope.launch {
70
+ try {
71
+ Beekon.start()
72
+ promise.resolve(null)
73
+ } catch (t: Throwable) {
74
+ promise.reject(errorCode(t), t.message ?: "start failed", t)
75
+ }
76
+ }
77
+ }
78
+
79
+ override fun stop(promise: Promise) {
80
+ scope.launch {
81
+ try {
82
+ Beekon.stop()
83
+ promise.resolve(null)
84
+ } catch (t: Throwable) {
85
+ promise.reject(errorCode(t), t.message ?: "stop failed", t)
86
+ }
87
+ }
88
+ }
89
+
90
+ // Android has no native resumeIfNeeded — Beekon.start() rehydrates the
91
+ // persisted intent (mirrors the Flutter plugin).
92
+ override fun resumeIfNeeded(promise: Promise) {
93
+ scope.launch {
94
+ try {
95
+ Beekon.start()
96
+ promise.resolve(null)
97
+ } catch (t: Throwable) {
98
+ promise.reject(errorCode(t), t.message ?: "resumeIfNeeded failed", t)
99
+ }
100
+ }
101
+ }
102
+
103
+ // ---------------------------------------------------------------------------
104
+ // History
105
+ // ---------------------------------------------------------------------------
106
+
107
+ override fun getLocations(fromMs: Double, toMs: Double, promise: Promise) {
108
+ scope.launch {
109
+ try {
110
+ val from = Instant.ofEpochMilli(fromMs.toLong())
111
+ val to = Instant.ofEpochMilli(toMs.toLong())
112
+ val arr: WritableArray = Arguments.createArray()
113
+ for (loc in Beekon.getLocations(from, to)) arr.pushMap(locationToWire(loc))
114
+ promise.resolve(arr)
115
+ } catch (t: Throwable) {
116
+ promise.reject(errorCode(t), t.message ?: "getLocations failed", t)
117
+ }
118
+ }
119
+ }
120
+
121
+ override fun deleteLocations(beforeMs: Double, promise: Promise) {
122
+ scope.launch {
123
+ try {
124
+ // Negative is the wire sentinel for "delete all" (no cutoff).
125
+ val before = if (beforeMs < 0) null else Instant.ofEpochMilli(beforeMs.toLong())
126
+ promise.resolve(Beekon.deleteLocations(before))
127
+ } catch (t: Throwable) {
128
+ promise.reject(errorCode(t), t.message ?: "deleteLocations failed", t)
129
+ }
130
+ }
131
+ }
132
+
133
+ override fun pendingUploadCount(promise: Promise) {
134
+ scope.launch {
135
+ try {
136
+ promise.resolve(Beekon.pendingUploadCount())
137
+ } catch (t: Throwable) {
138
+ promise.reject(errorCode(t), t.message ?: "pendingUploadCount failed", t)
139
+ }
140
+ }
141
+ }
142
+
143
+ // ---------------------------------------------------------------------------
144
+ // Sync
145
+ // ---------------------------------------------------------------------------
146
+
147
+ override fun sync(promise: Promise) {
148
+ Beekon.sync()
149
+ promise.resolve(null)
150
+ }
151
+
152
+ override fun setExtras(entries: ReadableArray, promise: Promise) {
153
+ Beekon.setExtras(entriesToMap(entries))
154
+ promise.resolve(null)
155
+ }
156
+
157
+ // ---------------------------------------------------------------------------
158
+ // Geofences
159
+ // ---------------------------------------------------------------------------
160
+
161
+ override fun addGeofences(geofences: ReadableArray, promise: Promise) {
162
+ scope.launch {
163
+ try {
164
+ Beekon.addGeofences(wireToGeofences(geofences))
165
+ promise.resolve(null)
166
+ } catch (t: Throwable) {
167
+ promise.reject(errorCode(t), t.message ?: "addGeofences failed", t)
168
+ }
169
+ }
170
+ }
171
+
172
+ override fun removeGeofences(ids: ReadableArray, promise: Promise) {
173
+ scope.launch {
174
+ try {
175
+ val list = (0 until ids.size()).mapNotNull { ids.getString(it) }
176
+ Beekon.removeGeofences(list)
177
+ promise.resolve(null)
178
+ } catch (t: Throwable) {
179
+ promise.reject(errorCode(t), t.message ?: "removeGeofences failed", t)
180
+ }
181
+ }
182
+ }
183
+
184
+ override fun listGeofences(promise: Promise) {
185
+ scope.launch {
186
+ try {
187
+ val arr: WritableArray = Arguments.createArray()
188
+ for (g in Beekon.listGeofences()) arr.pushMap(geofenceToWire(g))
189
+ promise.resolve(arr)
190
+ } catch (t: Throwable) {
191
+ promise.reject(errorCode(t), t.message ?: "listGeofences failed", t)
192
+ }
193
+ }
194
+ }
195
+
196
+ override fun invalidate() {
197
+ super.invalidate()
198
+ scope.cancel()
199
+ }
200
+
201
+ // ---------------------------------------------------------------------------
202
+ // Mappers: wire (ReadableMap/Array) → Kotlin
203
+ // ---------------------------------------------------------------------------
204
+
205
+ private fun wireToConfig(map: ReadableMap): BeekonConfig {
206
+ val sync =
207
+ if (map.hasKey("sync") && !map.isNull("sync")) {
208
+ map.getMap("sync")?.let { wireToSyncConfig(it) }
209
+ } else {
210
+ null
211
+ }
212
+ val notification =
213
+ if (map.hasKey("notification") && !map.isNull("notification")) {
214
+ map.getMap("notification")?.let { wireToNotification(it) }
215
+ } else {
216
+ null
217
+ }
218
+ return BeekonConfig(
219
+ minTimeBetweenLocationsSeconds =
220
+ map.getDouble("minTimeBetweenLocationsSeconds").toLong(),
221
+ minDistanceBetweenLocationsMeters =
222
+ map.getDouble("minDistanceBetweenLocationsMeters"),
223
+ accuracyMode = toAccuracyMode(map.getString("accuracyMode")),
224
+ whenStationary = toStationaryMode(map.getString("whenStationary")),
225
+ stationaryRadiusMeters = map.getDouble("stationaryRadiusMeters"),
226
+ detectActivity = map.getBoolean("detectActivity"),
227
+ sync = sync,
228
+ notification = notification ?: NotificationConfig(),
229
+ )
230
+ }
231
+
232
+ private fun wireToSyncConfig(map: ReadableMap): SyncConfig =
233
+ SyncConfig(
234
+ url = map.getString("url") ?: "",
235
+ headers = entriesToMap(map.getArray("headers")),
236
+ intervalSeconds = map.getDouble("intervalSeconds").toLong(),
237
+ batchSize = map.getDouble("batchSize").toInt(),
238
+ )
239
+
240
+ private fun wireToNotification(map: ReadableMap): NotificationConfig {
241
+ val title =
242
+ if (map.hasKey("title") && !map.isNull("title")) map.getString("title") else null
243
+ val text =
244
+ if (map.hasKey("text") && !map.isNull("text")) map.getString("text") else null
245
+ // Use the data-class default for `title` when the wire value is absent.
246
+ return if (title != null) {
247
+ NotificationConfig(title = title, text = text)
248
+ } else {
249
+ NotificationConfig(text = text)
250
+ }
251
+ }
252
+
253
+ private fun wireToGeofences(arr: ReadableArray): List<BeekonGeofence> {
254
+ val out = ArrayList<BeekonGeofence>(arr.size())
255
+ for (i in 0 until arr.size()) {
256
+ val m = arr.getMap(i) ?: continue
257
+ out += BeekonGeofence(
258
+ id = m.getString("id") ?: "",
259
+ latitude = m.getDouble("lat"),
260
+ longitude = m.getDouble("lng"),
261
+ radiusMeters = m.getDouble("radiusMeters"),
262
+ notifyOnEntry = m.getBoolean("notifyOnEntry"),
263
+ notifyOnExit = m.getBoolean("notifyOnExit"),
264
+ )
265
+ }
266
+ return out
267
+ }
268
+
269
+ private fun entriesToMap(arr: ReadableArray?): Map<String, String> {
270
+ if (arr == null) return emptyMap()
271
+ val out = LinkedHashMap<String, String>(arr.size())
272
+ for (i in 0 until arr.size()) {
273
+ val e = arr.getMap(i) ?: continue
274
+ val k = e.getString("key") ?: continue
275
+ val v = e.getString("value") ?: continue
276
+ out[k] = v
277
+ }
278
+ return out
279
+ }
280
+
281
+ // ---------------------------------------------------------------------------
282
+ // Mappers: Kotlin → wire (WritableMap)
283
+ // ---------------------------------------------------------------------------
284
+
285
+ private fun locationToWire(loc: Location): WritableMap {
286
+ val m = Arguments.createMap()
287
+ m.putString("id", loc.id)
288
+ m.putDouble("lat", loc.latitude)
289
+ m.putDouble("lng", loc.longitude)
290
+ m.putDouble("timestampMs", loc.timestamp.toEpochMilli().toDouble())
291
+ putNullableDouble(m, "accuracy", loc.accuracy)
292
+ putNullableDouble(m, "speed", loc.speed)
293
+ putNullableDouble(m, "bearing", loc.bearing)
294
+ putNullableDouble(m, "altitude", loc.altitude)
295
+ m.putString("quality", qualityToWire(loc.quality))
296
+ m.putString("trigger", triggerToWire(loc.trigger))
297
+ m.putString("motion", motionToWire(loc.motion))
298
+ val activity = loc.activity
299
+ if (activity != null) m.putString("activity", activityToWire(activity)) else m.putNull("activity")
300
+ m.putBoolean("isMock", loc.isMock)
301
+ return m
302
+ }
303
+
304
+ private fun geofenceToWire(g: BeekonGeofence): WritableMap {
305
+ val m = Arguments.createMap()
306
+ m.putString("id", g.id)
307
+ m.putDouble("lat", g.latitude)
308
+ m.putDouble("lng", g.longitude)
309
+ m.putDouble("radiusMeters", g.radiusMeters)
310
+ m.putBoolean("notifyOnEntry", g.notifyOnEntry)
311
+ m.putBoolean("notifyOnExit", g.notifyOnExit)
312
+ return m
313
+ }
314
+
315
+ private fun geofenceEventToWire(e: GeofenceEvent): WritableMap {
316
+ val m = Arguments.createMap()
317
+ m.putString("id", e.id)
318
+ m.putString("geofenceId", e.geofenceId)
319
+ m.putString("type", transitionToWire(e.type))
320
+ m.putDouble("timestampMs", e.timestamp.toEpochMilli().toDouble())
321
+ return m
322
+ }
323
+
324
+ private fun stateToWire(s: BeekonState): WritableMap {
325
+ val m = Arguments.createMap()
326
+ when (s) {
327
+ BeekonState.Idle -> m.putString("type", "idle")
328
+ BeekonState.Tracking -> m.putString("type", "tracking")
329
+ is BeekonState.Stopped -> {
330
+ m.putString("type", "stopped")
331
+ m.putString("stopReason", stopReasonToWire(s.reason))
332
+ }
333
+ }
334
+ return m
335
+ }
336
+
337
+ private fun syncStatusToWire(s: SyncStatus): WritableMap {
338
+ val m = Arguments.createMap()
339
+ when (s) {
340
+ SyncStatus.Idle -> m.putString("type", "idle")
341
+ SyncStatus.Pending -> m.putString("type", "pending")
342
+ is SyncStatus.Failed -> {
343
+ m.putString("type", "failed")
344
+ m.putString("failure", syncFailureToWire(s.reason))
345
+ }
346
+ }
347
+ return m
348
+ }
349
+
350
+ private fun putNullableDouble(map: WritableMap, key: String, value: Double?) {
351
+ if (value == null) map.putNull(key) else map.putDouble(key, value)
352
+ }
353
+
354
+ // ---------------------------------------------------------------------------
355
+ // Enum mappers
356
+ // ---------------------------------------------------------------------------
357
+
358
+ private fun toAccuracyMode(s: String?): AccuracyMode = when (s) {
359
+ "high" -> AccuracyMode.High
360
+ "low" -> AccuracyMode.Low
361
+ else -> AccuracyMode.Balanced
362
+ }
363
+
364
+ private fun toStationaryMode(s: String?): StationaryMode = when (s) {
365
+ "keepTracking" -> StationaryMode.KeepTracking
366
+ "pauseWithCheckIns" -> StationaryMode.PauseWithCheckIns
367
+ else -> StationaryMode.Pause
368
+ }
369
+
370
+ private fun stopReasonToWire(r: StopReason): String = when (r) {
371
+ StopReason.User -> "user"
372
+ StopReason.PermissionDenied -> "permissionDenied"
373
+ StopReason.LocationServicesDisabled -> "locationServicesDisabled"
374
+ StopReason.LocationUnavailable -> "locationUnavailable"
375
+ StopReason.System -> "system"
376
+ }
377
+
378
+ private fun syncFailureToWire(f: SyncFailure): String = when (f) {
379
+ SyncFailure.Auth -> "auth"
380
+ SyncFailure.Rejected -> "rejected"
381
+ }
382
+
383
+ private fun qualityToWire(q: LocationQuality): String = when (q) {
384
+ LocationQuality.Ok -> "ok"
385
+ LocationQuality.LowAccuracy -> "lowAccuracy"
386
+ LocationQuality.ImplausibleSpeed -> "implausibleSpeed"
387
+ }
388
+
389
+ private fun triggerToWire(t: LocationTrigger): String = when (t) {
390
+ LocationTrigger.Interval -> "interval"
391
+ LocationTrigger.Motion -> "motion"
392
+ LocationTrigger.CheckIn -> "checkIn"
393
+ LocationTrigger.Geofence -> "geofence"
394
+ LocationTrigger.Manual -> "manual"
395
+ }
396
+
397
+ private fun motionToWire(m: MotionState): String = when (m) {
398
+ MotionState.Moving -> "moving"
399
+ MotionState.Stationary -> "stationary"
400
+ MotionState.Unknown -> "unknown"
401
+ }
402
+
403
+ private fun activityToWire(a: ActivityType): String = when (a) {
404
+ ActivityType.Stationary -> "stationary"
405
+ ActivityType.Walking -> "walking"
406
+ ActivityType.Running -> "running"
407
+ ActivityType.Cycling -> "cycling"
408
+ ActivityType.Automotive -> "automotive"
409
+ ActivityType.Unknown -> "unknown"
410
+ }
411
+
412
+ private fun transitionToWire(t: Transition): String = when (t) {
413
+ Transition.Enter -> "enter"
414
+ Transition.Exit -> "exit"
415
+ }
416
+
417
+ // Maps native exceptions to stable JS-side codes, shared with iOS so JS can
418
+ // switch on them platform-agnostically.
419
+ private fun errorCode(t: Throwable): String = when (t) {
420
+ is BeekonException.StorageException -> "STORAGE_FAILURE"
421
+ is BeekonException.InvalidGeofence -> "INVALID_GEOFENCE"
422
+ else -> "INTERNAL_ERROR"
423
+ }
424
+
425
+ companion object {
426
+ const val NAME = NativeBeekonRnSpec.NAME
427
+ }
428
+ }
@@ -1,4 +1,4 @@
1
- package com.wayq.beekonrn
1
+ package `in`.wayq.beekonrn
2
2
 
3
3
  import com.facebook.react.BaseReactPackage
4
4
  import com.facebook.react.bridge.NativeModule
package/ios/BeekonRn.h CHANGED
@@ -1,5 +1,9 @@
1
1
  #import <BeekonRnSpec/BeekonRnSpec.h>
2
2
 
3
- @interface BeekonRn : NSObject <NativeBeekonRnSpec>
3
+ // Inherit from NativeBeekonRnSpecBase (codegen-provided) — it ships the
4
+ // concrete `emitOnState:` / `emitOnLocation:` implementations that bridge
5
+ // to JS via the EventEmitter callback. Conform to the protocol for the
6
+ // method-side TurboModule contract.
7
+ @interface BeekonRn : NativeBeekonRnSpecBase <NativeBeekonRnSpec>
4
8
 
5
9
  @end
package/ios/BeekonRn.mm CHANGED
@@ -1,6 +1,13 @@
1
1
  #import "BeekonRn.h"
2
- // Auto-generated bridging header from the Swift impl in this same target.
2
+ // Auto-generated Swift interop header for the BeekonRnImpl class. Its path
3
+ // depends on how the host links pods: under `<BeekonRn/…>` with
4
+ // `use_frameworks!` (framework), or as a same-target generated header with
5
+ // static linking (the React Native default). Support both.
6
+ #if __has_include(<BeekonRn/BeekonRn-Swift.h>)
7
+ #import <BeekonRn/BeekonRn-Swift.h>
8
+ #else
3
9
  #import "BeekonRn-Swift.h"
10
+ #endif
4
11
 
5
12
  @implementation BeekonRn {
6
13
  BeekonRnImpl *_impl;
@@ -11,39 +18,43 @@
11
18
  if (self) {
12
19
  __weak __typeof(self) weakSelf = self;
13
20
  _impl = [[BeekonRnImpl alloc]
14
- initWithOnState:^(NSDictionary *_Nonnull s) {
15
- [weakSelf emitOnState:s];
16
- }
17
- onPosition:^(NSDictionary *_Nonnull p) {
18
- [weakSelf emitOnPosition:p];
19
- }];
21
+ initOnState:^(NSDictionary *_Nonnull s) {
22
+ [weakSelf emitOnState:s];
23
+ }
24
+ onLocation:^(NSDictionary *_Nonnull l) {
25
+ [weakSelf emitOnLocation:l];
26
+ }
27
+ onGeofenceEvent:^(NSDictionary *_Nonnull e) {
28
+ [weakSelf emitOnGeofenceEvent:e];
29
+ }
30
+ onSyncStatus:^(NSDictionary *_Nonnull st) {
31
+ [weakSelf emitOnSyncStatus:st];
32
+ }];
20
33
  }
21
34
  return self;
22
35
  }
23
36
 
24
- - (void)initialize:(RCTPromiseResolveBlock)resolve
25
- reject:(RCTPromiseRejectBlock)reject {
26
- [_impl initializeWithResolver:resolve rejecter:reject];
37
+ // Called by React Native on teardown (RCTInvalidating). The Codegen base class
38
+ // derives from NSObject, which has no `invalidate`, so there's no super to call.
39
+ - (void)invalidate {
40
+ [_impl invalidate];
27
41
  }
28
42
 
29
- - (void)configure:(JS::NativeBeekonRn::WireConfig &)config
43
+ /// Registers Beekon's background tasks. Call from the host AppDelegate's
44
+ /// `application:didFinishLaunchingWithOptions:` (it must run before that method
45
+ /// returns). Exposed as a class method so hosts don't import BeekonKit directly.
46
+ + (void)registerBackgroundTasks {
47
+ [BeekonRnImpl registerBackgroundTasks];
48
+ }
49
+
50
+ // MARK: - Lifecycle
51
+
52
+ - (void)configure:(NSDictionary *)config
30
53
  resolve:(RCTPromiseResolveBlock)resolve
31
54
  reject:(RCTPromiseRejectBlock)reject {
32
- // Codegen passes the struct; round-trip through NSDictionary so the Swift
33
- // side can decode generically without an iOS-specific spec import.
34
- // (`config.toDictionary()` may also be available depending on RN version.)
35
- NSDictionary *dict = @{
36
- @"preset": config.preset() ?: @"balanced",
37
- @"distanceFilterMeters": config.distanceFilterMeters().has_value()
38
- ? @(config.distanceFilterMeters().value())
39
- : (id)[NSNull null],
40
- @"intervalMillis": config.intervalMillis().has_value()
41
- ? @(config.intervalMillis().value())
42
- : (id)[NSNull null],
43
- @"licenseKey": config.licenseKey() ?: (id)[NSNull null],
44
- };
45
- // Note: iOS doesn't use androidNotification — passed but ignored.
46
- [_impl configure:dict resolver:resolve rejecter:reject];
55
+ // The config crosses as a plain dictionary (UnsafeObject); the Swift side
56
+ // parses it. iOS ignores `notification` (Android-only).
57
+ [_impl configure:config resolver:resolve rejecter:reject];
47
58
  }
48
59
 
49
60
  - (void)start:(RCTPromiseResolveBlock)resolve
@@ -56,16 +67,61 @@
56
67
  [_impl stopWithResolver:resolve rejecter:reject];
57
68
  }
58
69
 
59
- - (void)shutdown:(RCTPromiseResolveBlock)resolve
60
- reject:(RCTPromiseRejectBlock)reject {
61
- [_impl shutdownWithResolver:resolve rejecter:reject];
70
+ - (void)resumeIfNeeded:(RCTPromiseResolveBlock)resolve
71
+ reject:(RCTPromiseRejectBlock)reject {
72
+ [_impl resumeIfNeededWithResolver:resolve rejecter:reject];
73
+ }
74
+
75
+ // MARK: - History
76
+
77
+ - (void)getLocations:(double)fromMs
78
+ toMs:(double)toMs
79
+ resolve:(RCTPromiseResolveBlock)resolve
80
+ reject:(RCTPromiseRejectBlock)reject {
81
+ [_impl getLocationsFromMs:fromMs toMs:toMs resolver:resolve rejecter:reject];
82
+ }
83
+
84
+ - (void)deleteLocations:(double)beforeMs
85
+ resolve:(RCTPromiseResolveBlock)resolve
86
+ reject:(RCTPromiseRejectBlock)reject {
87
+ [_impl deleteLocationsBeforeMs:beforeMs resolver:resolve rejecter:reject];
88
+ }
89
+
90
+ - (void)pendingUploadCount:(RCTPromiseResolveBlock)resolve
91
+ reject:(RCTPromiseRejectBlock)reject {
92
+ [_impl pendingUploadCountWithResolver:resolve rejecter:reject];
93
+ }
94
+
95
+ // MARK: - Sync
96
+
97
+ - (void)sync:(RCTPromiseResolveBlock)resolve
98
+ reject:(RCTPromiseRejectBlock)reject {
99
+ [_impl syncWithResolver:resolve rejecter:reject];
100
+ }
101
+
102
+ - (void)setExtras:(NSArray *)entries
103
+ resolve:(RCTPromiseResolveBlock)resolve
104
+ reject:(RCTPromiseRejectBlock)reject {
105
+ [_impl setExtras:entries resolver:resolve rejecter:reject];
106
+ }
107
+
108
+ // MARK: - Geofences
109
+
110
+ - (void)addGeofences:(NSArray *)geofences
111
+ resolve:(RCTPromiseResolveBlock)resolve
112
+ reject:(RCTPromiseRejectBlock)reject {
113
+ [_impl addGeofences:geofences resolver:resolve rejecter:reject];
114
+ }
115
+
116
+ - (void)removeGeofences:(NSArray *)ids
117
+ resolve:(RCTPromiseResolveBlock)resolve
118
+ reject:(RCTPromiseRejectBlock)reject {
119
+ [_impl removeGeofences:ids resolver:resolve rejecter:reject];
62
120
  }
63
121
 
64
- - (void)history:(double)fromMs
65
- toMs:(double)toMs
66
- resolve:(RCTPromiseResolveBlock)resolve
67
- reject:(RCTPromiseRejectBlock)reject {
68
- [_impl historyFromMs:fromMs toMs:toMs resolver:resolve rejecter:reject];
122
+ - (void)listGeofences:(RCTPromiseResolveBlock)resolve
123
+ reject:(RCTPromiseRejectBlock)reject {
124
+ [_impl listGeofencesWithResolver:resolve rejecter:reject];
69
125
  }
70
126
 
71
127
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule: