@wayq/beekon-rn 0.0.3 → 0.0.6
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.
- package/BeekonRn.podspec +5 -3
- package/CHANGELOG.md +103 -0
- package/README.md +326 -52
- package/android/build.gradle +9 -4
- package/android/src/main/java/in/wayq/beekonrn/BeekonRnModule.kt +411 -59
- package/ios/BeekonRn.mm +103 -24
- package/ios/BeekonRn.swift +465 -61
- package/ios/Frameworks/BeekonKit.xcframework/Info.plist +5 -5
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/BeekonKit +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Info.plist +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.abi.json +11424 -1279
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.swiftinterface +262 -36
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/BeekonKit +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Info.plist +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.abi.json +11424 -1279
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.swiftinterface +262 -36
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.abi.json +11424 -1279
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +262 -36
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/_CodeSignature/CodeResources +2 -80
- package/lib/module/NativeBeekonRn.js +35 -7
- package/lib/module/NativeBeekonRn.js.map +1 -1
- package/lib/module/beekon.js +246 -45
- package/lib/module/beekon.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal/mappers.js +166 -25
- package/lib/module/internal/mappers.js.map +1 -1
- package/lib/module/types/auth.js +4 -0
- package/lib/module/types/auth.js.map +1 -0
- package/lib/module/types/config.js +2 -0
- package/lib/module/types/enums.js +2 -0
- package/lib/module/types/enums.js.map +1 -0
- package/lib/module/types/error.js +20 -4
- package/lib/module/types/error.js.map +1 -1
- package/lib/module/types/geofence.js +2 -0
- package/lib/module/types/geofence.js.map +1 -0
- package/lib/module/types/location.js +2 -0
- package/lib/module/types/sync.js +2 -0
- package/lib/module/types/sync.js.map +1 -0
- package/lib/typescript/src/NativeBeekonRn.d.ts +150 -20
- package/lib/typescript/src/NativeBeekonRn.d.ts.map +1 -1
- package/lib/typescript/src/beekon.d.ts +110 -33
- package/lib/typescript/src/beekon.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +6 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/internal/mappers.d.ts +16 -6
- package/lib/typescript/src/internal/mappers.d.ts.map +1 -1
- package/lib/typescript/src/types/auth.d.ts +99 -0
- package/lib/typescript/src/types/auth.d.ts.map +1 -0
- package/lib/typescript/src/types/config.d.ts +66 -20
- package/lib/typescript/src/types/config.d.ts.map +1 -1
- package/lib/typescript/src/types/enums.d.ts +62 -0
- package/lib/typescript/src/types/enums.d.ts.map +1 -0
- package/lib/typescript/src/types/error.d.ts +21 -5
- package/lib/typescript/src/types/error.d.ts.map +1 -1
- package/lib/typescript/src/types/geofence.d.ts +36 -0
- package/lib/typescript/src/types/geofence.d.ts.map +1 -0
- package/lib/typescript/src/types/location.d.ts +22 -8
- package/lib/typescript/src/types/location.d.ts.map +1 -1
- package/lib/typescript/src/types/state.d.ts +13 -4
- package/lib/typescript/src/types/state.d.ts.map +1 -1
- package/lib/typescript/src/types/sync.d.ts +27 -0
- package/lib/typescript/src/types/sync.d.ts.map +1 -0
- package/package.json +8 -5
- package/scripts/fetch-beekonkit.sh +5 -5
- package/src/NativeBeekonRn.ts +165 -20
- package/src/beekon.ts +278 -48
- package/src/index.tsx +24 -2
- package/src/internal/mappers.ts +242 -27
- package/src/types/auth.ts +101 -0
- package/src/types/config.ts +68 -20
- package/src/types/enums.ts +80 -0
- package/src/types/error.ts +23 -5
- package/src/types/geofence.ts +37 -0
- package/src/types/location.ts +28 -8
- package/src/types/state.ts +13 -3
- package/src/types/sync.ts +23 -0
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeDirectory +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeRequirements +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeResources +0 -296
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeSignature +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/_CodeSignature/CodeResources +0 -146
|
@@ -3,54 +3,72 @@ package `in`.wayq.beekonrn
|
|
|
3
3
|
import com.facebook.react.bridge.Arguments
|
|
4
4
|
import com.facebook.react.bridge.Promise
|
|
5
5
|
import com.facebook.react.bridge.ReactApplicationContext
|
|
6
|
+
import com.facebook.react.bridge.ReadableArray
|
|
6
7
|
import com.facebook.react.bridge.ReadableMap
|
|
7
8
|
import com.facebook.react.bridge.WritableArray
|
|
8
9
|
import com.facebook.react.bridge.WritableMap
|
|
10
|
+
import `in`.wayq.beekon.AccuracyMode
|
|
11
|
+
import `in`.wayq.beekon.ActivityType
|
|
12
|
+
import `in`.wayq.beekon.AuthBodyFormat
|
|
13
|
+
import `in`.wayq.beekon.AuthConfig
|
|
14
|
+
import `in`.wayq.beekon.AuthResponseMapping
|
|
15
|
+
import `in`.wayq.beekon.AuthStrategy
|
|
16
|
+
import `in`.wayq.beekon.AuthTokens
|
|
9
17
|
import `in`.wayq.beekon.Beekon
|
|
10
18
|
import `in`.wayq.beekon.BeekonConfig
|
|
11
|
-
import `in`.wayq.beekon.
|
|
19
|
+
import `in`.wayq.beekon.BeekonException
|
|
20
|
+
import `in`.wayq.beekon.BeekonGeofence
|
|
12
21
|
import `in`.wayq.beekon.BeekonState
|
|
22
|
+
import `in`.wayq.beekon.GeofenceEvent
|
|
13
23
|
import `in`.wayq.beekon.Location
|
|
24
|
+
import `in`.wayq.beekon.LocationQuality
|
|
25
|
+
import `in`.wayq.beekon.LocationTrigger
|
|
26
|
+
import `in`.wayq.beekon.LocationUnavailableReason
|
|
27
|
+
import `in`.wayq.beekon.MotionState
|
|
28
|
+
import `in`.wayq.beekon.NotificationConfig
|
|
29
|
+
import `in`.wayq.beekon.StationaryMode
|
|
14
30
|
import `in`.wayq.beekon.StopReason
|
|
31
|
+
import `in`.wayq.beekon.SyncConfig
|
|
32
|
+
import `in`.wayq.beekon.SyncFailure
|
|
33
|
+
import `in`.wayq.beekon.SyncStatus
|
|
34
|
+
import `in`.wayq.beekon.Transition
|
|
15
35
|
import java.time.Instant
|
|
16
36
|
import kotlinx.coroutines.CoroutineScope
|
|
17
37
|
import kotlinx.coroutines.Dispatchers
|
|
18
|
-
import kotlinx.coroutines.Job
|
|
19
38
|
import kotlinx.coroutines.SupervisorJob
|
|
20
39
|
import kotlinx.coroutines.cancel
|
|
21
40
|
import kotlinx.coroutines.launch
|
|
22
41
|
|
|
23
|
-
class BeekonRnModule(
|
|
42
|
+
class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
24
43
|
NativeBeekonRnSpec(reactContext) {
|
|
25
44
|
|
|
26
45
|
// Default dispatcher (not Main.immediate) — Codegen's emitOnX is thread-safe
|
|
27
|
-
// and marshals to JS internally, so collecting on Main buys nothing and
|
|
28
|
-
//
|
|
29
|
-
//
|
|
46
|
+
// and marshals to JS internally, so collecting on Main buys nothing and risks
|
|
47
|
+
// jank if a mapper does work. SupervisorJob so one failing collector doesn't
|
|
48
|
+
// tear down its siblings.
|
|
30
49
|
private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
|
|
31
|
-
private var stateJob: Job? = null
|
|
32
|
-
private var locationsJob: Job? = null
|
|
33
50
|
|
|
34
51
|
init {
|
|
35
|
-
// Beekon.initialize
|
|
36
|
-
|
|
37
|
-
Beekon.
|
|
38
|
-
|
|
39
|
-
Beekon.
|
|
40
|
-
}
|
|
41
|
-
locationsJob = scope.launch {
|
|
42
|
-
Beekon.locations.collect { loc -> emitOnLocation(locationToWire(loc)) }
|
|
52
|
+
// No Beekon.initialize() — the SDK auto-initializes via AndroidX Startup.
|
|
53
|
+
scope.launch { Beekon.state.collect { emitOnState(stateToWire(it)) } }
|
|
54
|
+
scope.launch { Beekon.locations.collect { emitOnLocation(locationToWire(it)) } }
|
|
55
|
+
scope.launch {
|
|
56
|
+
Beekon.geofenceEvents.collect { emitOnGeofenceEvent(geofenceEventToWire(it)) }
|
|
43
57
|
}
|
|
58
|
+
scope.launch { Beekon.syncStatus.collect { emitOnSyncStatus(syncStatusToWire(it)) } }
|
|
59
|
+
scope.launch { Beekon.authChanges.collect { emitOnAuthTokens(tokenRefreshToWire(it)) } }
|
|
44
60
|
}
|
|
45
61
|
|
|
62
|
+
// ---------------------------------------------------------------------------
|
|
63
|
+
// Lifecycle (non-suspend native calls resolve directly)
|
|
64
|
+
// ---------------------------------------------------------------------------
|
|
65
|
+
|
|
46
66
|
override fun configure(config: ReadableMap, promise: Promise) {
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
promise.reject(errorCode(t), t.message ?: "configure failed", t)
|
|
53
|
-
}
|
|
67
|
+
try {
|
|
68
|
+
Beekon.configure(wireToConfig(config))
|
|
69
|
+
promise.resolve(null)
|
|
70
|
+
} catch (t: Throwable) {
|
|
71
|
+
promise.reject(errorCode(t), t.message ?: "configure failed", t)
|
|
54
72
|
}
|
|
55
73
|
}
|
|
56
74
|
|
|
@@ -76,17 +94,124 @@ class BeekonRnModule(private val reactContext: ReactApplicationContext) :
|
|
|
76
94
|
}
|
|
77
95
|
}
|
|
78
96
|
|
|
79
|
-
|
|
97
|
+
// Calls the guarded native resume (Beekon.resumeIfNeeded), which only
|
|
98
|
+
// re-adopts a previously-active, non-user-stopped session — a no-op when
|
|
99
|
+
// already Tracking or when the user explicitly stopped (mirrors iOS).
|
|
100
|
+
override fun resumeIfNeeded(promise: Promise) {
|
|
101
|
+
scope.launch {
|
|
102
|
+
try {
|
|
103
|
+
Beekon.resumeIfNeeded()
|
|
104
|
+
promise.resolve(null)
|
|
105
|
+
} catch (t: Throwable) {
|
|
106
|
+
promise.reject(errorCode(t), t.message ?: "resumeIfNeeded failed", t)
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
override fun getCurrentLocation(timeoutMs: Double, accuracy: String, promise: Promise) {
|
|
112
|
+
scope.launch {
|
|
113
|
+
try {
|
|
114
|
+
// Empty accuracy is the wire encoding of "use the configured mode".
|
|
115
|
+
val mode = if (accuracy.isEmpty()) null else toAccuracyMode(accuracy)
|
|
116
|
+
val loc = Beekon.getCurrentLocation(timeoutMs.toLong(), mode)
|
|
117
|
+
val arr: WritableArray = Arguments.createArray()
|
|
118
|
+
if (loc != null) arr.pushMap(locationToWire(loc))
|
|
119
|
+
promise.resolve(arr)
|
|
120
|
+
} catch (t: Throwable) {
|
|
121
|
+
promise.reject(errorCode(t), t.message ?: "getCurrentLocation failed", t)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// ---------------------------------------------------------------------------
|
|
127
|
+
// History
|
|
128
|
+
// ---------------------------------------------------------------------------
|
|
129
|
+
|
|
130
|
+
override fun getLocations(fromMs: Double, toMs: Double, promise: Promise) {
|
|
80
131
|
scope.launch {
|
|
81
132
|
try {
|
|
82
133
|
val from = Instant.ofEpochMilli(fromMs.toLong())
|
|
83
134
|
val to = Instant.ofEpochMilli(toMs.toLong())
|
|
84
|
-
val locations = Beekon.history(from, to)
|
|
85
135
|
val arr: WritableArray = Arguments.createArray()
|
|
86
|
-
for (loc in
|
|
136
|
+
for (loc in Beekon.getLocations(from, to)) arr.pushMap(locationToWire(loc))
|
|
87
137
|
promise.resolve(arr)
|
|
88
138
|
} catch (t: Throwable) {
|
|
89
|
-
promise.reject(errorCode(t), t.message ?: "
|
|
139
|
+
promise.reject(errorCode(t), t.message ?: "getLocations failed", t)
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
override fun deleteLocations(beforeMs: Double, promise: Promise) {
|
|
145
|
+
scope.launch {
|
|
146
|
+
try {
|
|
147
|
+
// Negative is the wire sentinel for "delete all" (no cutoff).
|
|
148
|
+
val before = if (beforeMs < 0) null else Instant.ofEpochMilli(beforeMs.toLong())
|
|
149
|
+
promise.resolve(Beekon.deleteLocations(before))
|
|
150
|
+
} catch (t: Throwable) {
|
|
151
|
+
promise.reject(errorCode(t), t.message ?: "deleteLocations failed", t)
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
override fun pendingUploadCount(promise: Promise) {
|
|
157
|
+
scope.launch {
|
|
158
|
+
try {
|
|
159
|
+
promise.resolve(Beekon.pendingUploadCount())
|
|
160
|
+
} catch (t: Throwable) {
|
|
161
|
+
promise.reject(errorCode(t), t.message ?: "pendingUploadCount failed", t)
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
// ---------------------------------------------------------------------------
|
|
167
|
+
// Sync
|
|
168
|
+
// ---------------------------------------------------------------------------
|
|
169
|
+
|
|
170
|
+
override fun sync(promise: Promise) {
|
|
171
|
+
Beekon.sync()
|
|
172
|
+
promise.resolve(null)
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
override fun setExtras(entries: ReadableArray, promise: Promise) {
|
|
176
|
+
Beekon.setExtras(entriesToMap(entries))
|
|
177
|
+
promise.resolve(null)
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// ---------------------------------------------------------------------------
|
|
181
|
+
// Geofences
|
|
182
|
+
// ---------------------------------------------------------------------------
|
|
183
|
+
|
|
184
|
+
override fun addGeofences(geofences: ReadableArray, promise: Promise) {
|
|
185
|
+
scope.launch {
|
|
186
|
+
try {
|
|
187
|
+
Beekon.addGeofences(wireToGeofences(geofences))
|
|
188
|
+
promise.resolve(null)
|
|
189
|
+
} catch (t: Throwable) {
|
|
190
|
+
promise.reject(errorCode(t), t.message ?: "addGeofences failed", t)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
override fun removeGeofences(ids: ReadableArray, promise: Promise) {
|
|
196
|
+
scope.launch {
|
|
197
|
+
try {
|
|
198
|
+
val list = (0 until ids.size()).mapNotNull { ids.getString(it) }
|
|
199
|
+
Beekon.removeGeofences(list)
|
|
200
|
+
promise.resolve(null)
|
|
201
|
+
} catch (t: Throwable) {
|
|
202
|
+
promise.reject(errorCode(t), t.message ?: "removeGeofences failed", t)
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
override fun listGeofences(promise: Promise) {
|
|
208
|
+
scope.launch {
|
|
209
|
+
try {
|
|
210
|
+
val arr: WritableArray = Arguments.createArray()
|
|
211
|
+
for (g in Beekon.listGeofences()) arr.pushMap(geofenceToWire(g))
|
|
212
|
+
promise.resolve(arr)
|
|
213
|
+
} catch (t: Throwable) {
|
|
214
|
+
promise.reject(errorCode(t), t.message ?: "listGeofences failed", t)
|
|
90
215
|
}
|
|
91
216
|
}
|
|
92
217
|
}
|
|
@@ -97,54 +222,182 @@ class BeekonRnModule(private val reactContext: ReactApplicationContext) :
|
|
|
97
222
|
}
|
|
98
223
|
|
|
99
224
|
// ---------------------------------------------------------------------------
|
|
100
|
-
// Mappers (
|
|
225
|
+
// Mappers: wire (ReadableMap/Array) → Kotlin
|
|
101
226
|
// ---------------------------------------------------------------------------
|
|
102
227
|
|
|
103
228
|
private fun wireToConfig(map: ReadableMap): BeekonConfig {
|
|
104
|
-
val
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
229
|
+
val sync =
|
|
230
|
+
if (map.hasKey("sync") && !map.isNull("sync")) {
|
|
231
|
+
map.getMap("sync")?.let { wireToSyncConfig(it) }
|
|
232
|
+
} else {
|
|
233
|
+
null
|
|
234
|
+
}
|
|
235
|
+
val notification =
|
|
236
|
+
if (map.hasKey("notification") && !map.isNull("notification")) {
|
|
237
|
+
map.getMap("notification")?.let { wireToNotification(it) }
|
|
238
|
+
} else {
|
|
239
|
+
null
|
|
240
|
+
}
|
|
109
241
|
return BeekonConfig(
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
242
|
+
minTimeBetweenLocationsSeconds =
|
|
243
|
+
map.getDouble("minTimeBetweenLocationsSeconds").toLong(),
|
|
244
|
+
minDistanceBetweenLocationsMeters =
|
|
245
|
+
map.getDouble("minDistanceBetweenLocationsMeters"),
|
|
246
|
+
accuracyMode = toAccuracyMode(map.getString("accuracyMode")),
|
|
247
|
+
whenStationary = toStationaryMode(map.getString("whenStationary")),
|
|
248
|
+
stationaryRadiusMeters = map.getDouble("stationaryRadiusMeters"),
|
|
249
|
+
detectActivity = map.getBoolean("detectActivity"),
|
|
250
|
+
sync = sync,
|
|
251
|
+
notification = notification ?: NotificationConfig(),
|
|
252
|
+
)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
private fun wireToSyncConfig(map: ReadableMap): SyncConfig {
|
|
256
|
+
val auth =
|
|
257
|
+
if (map.hasKey("auth") && !map.isNull("auth")) {
|
|
258
|
+
map.getMap("auth")?.let { wireToAuthConfig(it) }
|
|
259
|
+
} else {
|
|
260
|
+
null
|
|
261
|
+
}
|
|
262
|
+
return SyncConfig(
|
|
263
|
+
url = map.getString("url") ?: "",
|
|
264
|
+
headers = entriesToMap(map.getArray("headers")),
|
|
265
|
+
intervalSeconds = map.getDouble("intervalSeconds").toLong(),
|
|
266
|
+
batchSize = map.getDouble("batchSize").toInt(),
|
|
267
|
+
auth = auth,
|
|
113
268
|
)
|
|
114
269
|
}
|
|
115
270
|
|
|
116
|
-
private fun
|
|
117
|
-
val
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
val smallIcon: Int? = resName?.let {
|
|
124
|
-
val pkg = reactContext.packageName
|
|
125
|
-
val id = reactContext.resources.getIdentifier(it, "drawable", pkg)
|
|
126
|
-
if (id == 0) {
|
|
127
|
-
throw IllegalArgumentException("drawable resource '$it' not found in package '$pkg'")
|
|
271
|
+
private fun wireToAuthConfig(map: ReadableMap): AuthConfig {
|
|
272
|
+
val expiresAt =
|
|
273
|
+
if (map.hasKey("expiresAtMs") && !map.isNull("expiresAtMs")) {
|
|
274
|
+
// Wire carries epoch millis; the native recipe wants epoch seconds.
|
|
275
|
+
(map.getDouble("expiresAtMs") / 1000.0).toLong()
|
|
276
|
+
} else {
|
|
277
|
+
null
|
|
128
278
|
}
|
|
129
|
-
|
|
279
|
+
val seedEpoch =
|
|
280
|
+
if (map.hasKey("seedEpoch") && !map.isNull("seedEpoch")) {
|
|
281
|
+
map.getDouble("seedEpoch").toLong()
|
|
282
|
+
} else {
|
|
283
|
+
null
|
|
284
|
+
}
|
|
285
|
+
val responseMapping =
|
|
286
|
+
if (map.hasKey("responseMapping") && !map.isNull("responseMapping")) {
|
|
287
|
+
map.getMap("responseMapping")?.let { wireToResponseMapping(it) } ?: AuthResponseMapping()
|
|
288
|
+
} else {
|
|
289
|
+
AuthResponseMapping()
|
|
290
|
+
}
|
|
291
|
+
return AuthConfig(
|
|
292
|
+
accessToken = optString(map, "accessToken"),
|
|
293
|
+
refreshToken = optString(map, "refreshToken"),
|
|
294
|
+
expiresAt = expiresAt,
|
|
295
|
+
strategy = toAuthStrategy(map.getString("strategy")),
|
|
296
|
+
refreshUrl = optString(map, "refreshUrl"),
|
|
297
|
+
refreshPayload = entriesToMap(map.getArray("refreshPayload")),
|
|
298
|
+
refreshHeaders = entriesToMap(map.getArray("refreshHeaders")),
|
|
299
|
+
refreshBodyFormat = toRefreshBodyFormat(map.getString("refreshBodyFormat")),
|
|
300
|
+
responseMapping = responseMapping,
|
|
301
|
+
skewMarginSeconds = map.getDouble("skewMarginSeconds").toLong(),
|
|
302
|
+
seedEpoch = seedEpoch,
|
|
303
|
+
)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
private fun wireToResponseMapping(map: ReadableMap): AuthResponseMapping =
|
|
307
|
+
AuthResponseMapping(
|
|
308
|
+
accessToken = optString(map, "accessToken"),
|
|
309
|
+
refreshToken = optString(map, "refreshToken"),
|
|
310
|
+
expiresIn = optString(map, "expiresIn"),
|
|
311
|
+
expiresAt = optString(map, "expiresAt"),
|
|
312
|
+
)
|
|
313
|
+
|
|
314
|
+
private fun optString(map: ReadableMap, key: String): String? =
|
|
315
|
+
if (map.hasKey(key) && !map.isNull(key)) map.getString(key) else null
|
|
316
|
+
|
|
317
|
+
private fun wireToNotification(map: ReadableMap): NotificationConfig {
|
|
318
|
+
val title =
|
|
319
|
+
if (map.hasKey("title") && !map.isNull("title")) map.getString("title") else null
|
|
320
|
+
val text =
|
|
321
|
+
if (map.hasKey("text") && !map.isNull("text")) map.getString("text") else null
|
|
322
|
+
val smallIcon =
|
|
323
|
+
if (map.hasKey("smallIcon") && !map.isNull("smallIcon")) map.getString("smallIcon") else null
|
|
324
|
+
// Use the data-class default for `title` when the wire value is absent.
|
|
325
|
+
return if (title != null) {
|
|
326
|
+
NotificationConfig(title = title, text = text, smallIcon = smallIcon)
|
|
327
|
+
} else {
|
|
328
|
+
NotificationConfig(text = text, smallIcon = smallIcon)
|
|
130
329
|
}
|
|
131
|
-
return BeekonConfig.Notification(title = title, text = text, smallIcon = smallIcon)
|
|
132
330
|
}
|
|
133
331
|
|
|
332
|
+
private fun wireToGeofences(arr: ReadableArray): List<BeekonGeofence> {
|
|
333
|
+
val out = ArrayList<BeekonGeofence>(arr.size())
|
|
334
|
+
for (i in 0 until arr.size()) {
|
|
335
|
+
val m = arr.getMap(i) ?: continue
|
|
336
|
+
out += BeekonGeofence(
|
|
337
|
+
id = m.getString("id") ?: "",
|
|
338
|
+
latitude = m.getDouble("lat"),
|
|
339
|
+
longitude = m.getDouble("lng"),
|
|
340
|
+
radiusMeters = m.getDouble("radiusMeters"),
|
|
341
|
+
notifyOnEntry = m.getBoolean("notifyOnEntry"),
|
|
342
|
+
notifyOnExit = m.getBoolean("notifyOnExit"),
|
|
343
|
+
)
|
|
344
|
+
}
|
|
345
|
+
return out
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
private fun entriesToMap(arr: ReadableArray?): Map<String, String> {
|
|
349
|
+
if (arr == null) return emptyMap()
|
|
350
|
+
val out = LinkedHashMap<String, String>(arr.size())
|
|
351
|
+
for (i in 0 until arr.size()) {
|
|
352
|
+
val e = arr.getMap(i) ?: continue
|
|
353
|
+
val k = e.getString("key") ?: continue
|
|
354
|
+
val v = e.getString("value") ?: continue
|
|
355
|
+
out[k] = v
|
|
356
|
+
}
|
|
357
|
+
return out
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
// ---------------------------------------------------------------------------
|
|
361
|
+
// Mappers: Kotlin → wire (WritableMap)
|
|
362
|
+
// ---------------------------------------------------------------------------
|
|
363
|
+
|
|
134
364
|
private fun locationToWire(loc: Location): WritableMap {
|
|
135
365
|
val m = Arguments.createMap()
|
|
136
|
-
m.
|
|
137
|
-
m.putDouble("
|
|
366
|
+
m.putString("id", loc.id)
|
|
367
|
+
m.putDouble("lat", loc.latitude)
|
|
368
|
+
m.putDouble("lng", loc.longitude)
|
|
138
369
|
m.putDouble("timestampMs", loc.timestamp.toEpochMilli().toDouble())
|
|
139
370
|
putNullableDouble(m, "accuracy", loc.accuracy)
|
|
140
371
|
putNullableDouble(m, "speed", loc.speed)
|
|
141
372
|
putNullableDouble(m, "bearing", loc.bearing)
|
|
142
373
|
putNullableDouble(m, "altitude", loc.altitude)
|
|
374
|
+
m.putString("quality", qualityToWire(loc.quality))
|
|
375
|
+
m.putString("trigger", triggerToWire(loc.trigger))
|
|
376
|
+
m.putString("motion", motionToWire(loc.motion))
|
|
377
|
+
val activity = loc.activity
|
|
378
|
+
if (activity != null) m.putString("activity", activityToWire(activity)) else m.putNull("activity")
|
|
379
|
+
m.putBoolean("isMock", loc.isMock)
|
|
143
380
|
return m
|
|
144
381
|
}
|
|
145
382
|
|
|
146
|
-
private fun
|
|
147
|
-
|
|
383
|
+
private fun geofenceToWire(g: BeekonGeofence): WritableMap {
|
|
384
|
+
val m = Arguments.createMap()
|
|
385
|
+
m.putString("id", g.id)
|
|
386
|
+
m.putDouble("lat", g.latitude)
|
|
387
|
+
m.putDouble("lng", g.longitude)
|
|
388
|
+
m.putDouble("radiusMeters", g.radiusMeters)
|
|
389
|
+
m.putBoolean("notifyOnEntry", g.notifyOnEntry)
|
|
390
|
+
m.putBoolean("notifyOnExit", g.notifyOnExit)
|
|
391
|
+
return m
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
private fun geofenceEventToWire(e: GeofenceEvent): WritableMap {
|
|
395
|
+
val m = Arguments.createMap()
|
|
396
|
+
m.putString("id", e.id)
|
|
397
|
+
m.putString("geofenceId", e.geofenceId)
|
|
398
|
+
m.putString("type", transitionToWire(e.type))
|
|
399
|
+
m.putDouble("timestampMs", e.timestamp.toEpochMilli().toDouble())
|
|
400
|
+
return m
|
|
148
401
|
}
|
|
149
402
|
|
|
150
403
|
private fun stateToWire(s: BeekonState): WritableMap {
|
|
@@ -160,19 +413,118 @@ class BeekonRnModule(private val reactContext: ReactApplicationContext) :
|
|
|
160
413
|
return m
|
|
161
414
|
}
|
|
162
415
|
|
|
416
|
+
private fun syncStatusToWire(s: SyncStatus): WritableMap {
|
|
417
|
+
val m = Arguments.createMap()
|
|
418
|
+
when (s) {
|
|
419
|
+
SyncStatus.Idle -> m.putString("type", "idle")
|
|
420
|
+
SyncStatus.Pending -> m.putString("type", "pending")
|
|
421
|
+
is SyncStatus.Failed -> {
|
|
422
|
+
m.putString("type", "failed")
|
|
423
|
+
m.putString("failure", syncFailureToWire(s.reason))
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
return m
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
private fun tokenRefreshToWire(t: AuthTokens): WritableMap {
|
|
430
|
+
val m = Arguments.createMap()
|
|
431
|
+
m.putString("accessToken", t.accessToken)
|
|
432
|
+
val refreshToken = t.refreshToken
|
|
433
|
+
if (refreshToken != null) m.putString("refreshToken", refreshToken) else m.putNull("refreshToken")
|
|
434
|
+
val expiresAt = t.expiresAt
|
|
435
|
+
// Native epoch seconds → wire epoch millis.
|
|
436
|
+
if (expiresAt != null) m.putDouble("expiresAtMs", (expiresAt * 1000L).toDouble()) else m.putNull("expiresAtMs")
|
|
437
|
+
m.putDouble("epoch", t.epoch.toDouble())
|
|
438
|
+
return m
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
private fun putNullableDouble(map: WritableMap, key: String, value: Double?) {
|
|
442
|
+
if (value == null) map.putNull(key) else map.putDouble(key, value)
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
// ---------------------------------------------------------------------------
|
|
446
|
+
// Enum mappers
|
|
447
|
+
// ---------------------------------------------------------------------------
|
|
448
|
+
|
|
449
|
+
private fun toAccuracyMode(s: String?): AccuracyMode = when (s) {
|
|
450
|
+
"high" -> AccuracyMode.High
|
|
451
|
+
"low" -> AccuracyMode.Low
|
|
452
|
+
else -> AccuracyMode.Balanced
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
private fun toStationaryMode(s: String?): StationaryMode = when (s) {
|
|
456
|
+
"keepTracking" -> StationaryMode.KeepTracking
|
|
457
|
+
"pauseWithCheckIns" -> StationaryMode.PauseWithCheckIns
|
|
458
|
+
else -> StationaryMode.Pause
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
private fun toAuthStrategy(s: String?): AuthStrategy = when (s) {
|
|
462
|
+
"raw" -> AuthStrategy.Raw
|
|
463
|
+
else -> AuthStrategy.Bearer
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
private fun toRefreshBodyFormat(s: String?): AuthBodyFormat = when (s) {
|
|
467
|
+
"json" -> AuthBodyFormat.Json
|
|
468
|
+
else -> AuthBodyFormat.Form
|
|
469
|
+
}
|
|
470
|
+
|
|
163
471
|
private fun stopReasonToWire(r: StopReason): String = when (r) {
|
|
164
472
|
StopReason.User -> "user"
|
|
165
473
|
StopReason.PermissionDenied -> "permissionDenied"
|
|
166
474
|
StopReason.LocationServicesDisabled -> "locationServicesDisabled"
|
|
475
|
+
StopReason.LocationUnavailable -> "locationUnavailable"
|
|
167
476
|
StopReason.System -> "system"
|
|
168
477
|
}
|
|
169
478
|
|
|
170
|
-
|
|
171
|
-
|
|
479
|
+
private fun syncFailureToWire(f: SyncFailure): String = when (f) {
|
|
480
|
+
SyncFailure.Auth -> "auth"
|
|
481
|
+
SyncFailure.Rejected -> "rejected"
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
private fun qualityToWire(q: LocationQuality): String = when (q) {
|
|
485
|
+
LocationQuality.Ok -> "ok"
|
|
486
|
+
LocationQuality.LowAccuracy -> "lowAccuracy"
|
|
487
|
+
LocationQuality.ImplausibleSpeed -> "implausibleSpeed"
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
private fun triggerToWire(t: LocationTrigger): String = when (t) {
|
|
491
|
+
LocationTrigger.Interval -> "interval"
|
|
492
|
+
LocationTrigger.Motion -> "motion"
|
|
493
|
+
LocationTrigger.CheckIn -> "checkIn"
|
|
494
|
+
LocationTrigger.Geofence -> "geofence"
|
|
495
|
+
LocationTrigger.Manual -> "manual"
|
|
496
|
+
}
|
|
497
|
+
|
|
498
|
+
private fun motionToWire(m: MotionState): String = when (m) {
|
|
499
|
+
MotionState.Moving -> "moving"
|
|
500
|
+
MotionState.Stationary -> "stationary"
|
|
501
|
+
MotionState.Unknown -> "unknown"
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
private fun activityToWire(a: ActivityType): String = when (a) {
|
|
505
|
+
ActivityType.Stationary -> "stationary"
|
|
506
|
+
ActivityType.Walking -> "walking"
|
|
507
|
+
ActivityType.Running -> "running"
|
|
508
|
+
ActivityType.Cycling -> "cycling"
|
|
509
|
+
ActivityType.Automotive -> "automotive"
|
|
510
|
+
ActivityType.Unknown -> "unknown"
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
private fun transitionToWire(t: Transition): String = when (t) {
|
|
514
|
+
Transition.Enter -> "enter"
|
|
515
|
+
Transition.Exit -> "exit"
|
|
516
|
+
}
|
|
517
|
+
|
|
518
|
+
// Maps native exceptions to stable JS-side codes, shared with iOS so JS can
|
|
519
|
+
// switch on them platform-agnostically.
|
|
172
520
|
private fun errorCode(t: Throwable): String = when (t) {
|
|
173
|
-
is
|
|
174
|
-
is
|
|
175
|
-
is
|
|
521
|
+
is BeekonException.StorageException -> "STORAGE_FAILURE"
|
|
522
|
+
is BeekonException.InvalidGeofence -> "INVALID_GEOFENCE"
|
|
523
|
+
is BeekonException.LocationUnavailable -> when (t.reason) {
|
|
524
|
+
LocationUnavailableReason.PermissionDenied -> "PERMISSION_DENIED"
|
|
525
|
+
LocationUnavailableReason.LocationServicesDisabled -> "LOCATION_SERVICES_DISABLED"
|
|
526
|
+
LocationUnavailableReason.Unavailable -> "LOCATION_UNAVAILABLE"
|
|
527
|
+
}
|
|
176
528
|
else -> "INTERNAL_ERROR"
|
|
177
529
|
}
|
|
178
530
|
|