@wayq/beekon-rn 0.0.5 → 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 +4 -2
- package/CHANGELOG.md +103 -0
- package/README.md +303 -81
- package/android/build.gradle +1 -1
- package/android/src/main/java/in/wayq/beekonrn/BeekonRnModule.kt +113 -7
- package/ios/BeekonRn.mm +13 -0
- package/ios/BeekonRn.swift +113 -9
- 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 +5399 -1463
- 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 +77 -2
- 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 +5399 -1463
- 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 +77 -2
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.abi.json +5399 -1463
- 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 +77 -2
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/_CodeSignature/CodeResources +1 -1
- package/lib/module/NativeBeekonRn.js +13 -0
- package/lib/module/NativeBeekonRn.js.map +1 -1
- package/lib/module/beekon.js +56 -7
- package/lib/module/beekon.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal/mappers.js +50 -3
- 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/error.js +13 -3
- package/lib/module/types/error.js.map +1 -1
- package/lib/typescript/src/NativeBeekonRn.d.ts +48 -0
- package/lib/typescript/src/NativeBeekonRn.d.ts.map +1 -1
- package/lib/typescript/src/beekon.d.ts +30 -1
- package/lib/typescript/src/beekon.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -1
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/internal/mappers.d.ts +5 -1
- 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 +16 -0
- package/lib/typescript/src/types/config.d.ts.map +1 -1
- package/lib/typescript/src/types/enums.d.ts +14 -0
- package/lib/typescript/src/types/enums.d.ts.map +1 -1
- package/lib/typescript/src/types/error.d.ts +14 -4
- package/lib/typescript/src/types/error.d.ts.map +1 -1
- package/package.json +5 -1
- package/scripts/fetch-beekonkit.sh +4 -4
- package/src/NativeBeekonRn.ts +55 -0
- package/src/beekon.ts +66 -6
- package/src/index.tsx +3 -0
- package/src/internal/mappers.ts +59 -1
- package/src/types/auth.ts +101 -0
- package/src/types/config.ts +16 -0
- package/src/types/enums.ts +16 -0
- package/src/types/error.ts +19 -4
|
@@ -9,6 +9,11 @@ import com.facebook.react.bridge.WritableArray
|
|
|
9
9
|
import com.facebook.react.bridge.WritableMap
|
|
10
10
|
import `in`.wayq.beekon.AccuracyMode
|
|
11
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
|
|
12
17
|
import `in`.wayq.beekon.Beekon
|
|
13
18
|
import `in`.wayq.beekon.BeekonConfig
|
|
14
19
|
import `in`.wayq.beekon.BeekonException
|
|
@@ -18,6 +23,7 @@ import `in`.wayq.beekon.GeofenceEvent
|
|
|
18
23
|
import `in`.wayq.beekon.Location
|
|
19
24
|
import `in`.wayq.beekon.LocationQuality
|
|
20
25
|
import `in`.wayq.beekon.LocationTrigger
|
|
26
|
+
import `in`.wayq.beekon.LocationUnavailableReason
|
|
21
27
|
import `in`.wayq.beekon.MotionState
|
|
22
28
|
import `in`.wayq.beekon.NotificationConfig
|
|
23
29
|
import `in`.wayq.beekon.StationaryMode
|
|
@@ -50,6 +56,7 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
50
56
|
Beekon.geofenceEvents.collect { emitOnGeofenceEvent(geofenceEventToWire(it)) }
|
|
51
57
|
}
|
|
52
58
|
scope.launch { Beekon.syncStatus.collect { emitOnSyncStatus(syncStatusToWire(it)) } }
|
|
59
|
+
scope.launch { Beekon.authChanges.collect { emitOnAuthTokens(tokenRefreshToWire(it)) } }
|
|
53
60
|
}
|
|
54
61
|
|
|
55
62
|
// ---------------------------------------------------------------------------
|
|
@@ -87,12 +94,13 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
87
94
|
}
|
|
88
95
|
}
|
|
89
96
|
|
|
90
|
-
//
|
|
91
|
-
//
|
|
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).
|
|
92
100
|
override fun resumeIfNeeded(promise: Promise) {
|
|
93
101
|
scope.launch {
|
|
94
102
|
try {
|
|
95
|
-
Beekon.
|
|
103
|
+
Beekon.resumeIfNeeded()
|
|
96
104
|
promise.resolve(null)
|
|
97
105
|
} catch (t: Throwable) {
|
|
98
106
|
promise.reject(errorCode(t), t.message ?: "resumeIfNeeded failed", t)
|
|
@@ -100,6 +108,21 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
100
108
|
}
|
|
101
109
|
}
|
|
102
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
|
+
|
|
103
126
|
// ---------------------------------------------------------------------------
|
|
104
127
|
// History
|
|
105
128
|
// ---------------------------------------------------------------------------
|
|
@@ -229,24 +252,80 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
229
252
|
)
|
|
230
253
|
}
|
|
231
254
|
|
|
232
|
-
private fun wireToSyncConfig(map: ReadableMap): SyncConfig
|
|
233
|
-
|
|
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(
|
|
234
263
|
url = map.getString("url") ?: "",
|
|
235
264
|
headers = entriesToMap(map.getArray("headers")),
|
|
236
265
|
intervalSeconds = map.getDouble("intervalSeconds").toLong(),
|
|
237
266
|
batchSize = map.getDouble("batchSize").toInt(),
|
|
267
|
+
auth = auth,
|
|
238
268
|
)
|
|
269
|
+
}
|
|
270
|
+
|
|
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
|
|
278
|
+
}
|
|
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
|
|
239
316
|
|
|
240
317
|
private fun wireToNotification(map: ReadableMap): NotificationConfig {
|
|
241
318
|
val title =
|
|
242
319
|
if (map.hasKey("title") && !map.isNull("title")) map.getString("title") else null
|
|
243
320
|
val text =
|
|
244
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
|
|
245
324
|
// Use the data-class default for `title` when the wire value is absent.
|
|
246
325
|
return if (title != null) {
|
|
247
|
-
NotificationConfig(title = title, text = text)
|
|
326
|
+
NotificationConfig(title = title, text = text, smallIcon = smallIcon)
|
|
248
327
|
} else {
|
|
249
|
-
NotificationConfig(text = text)
|
|
328
|
+
NotificationConfig(text = text, smallIcon = smallIcon)
|
|
250
329
|
}
|
|
251
330
|
}
|
|
252
331
|
|
|
@@ -347,6 +426,18 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
347
426
|
return m
|
|
348
427
|
}
|
|
349
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
|
+
|
|
350
441
|
private fun putNullableDouble(map: WritableMap, key: String, value: Double?) {
|
|
351
442
|
if (value == null) map.putNull(key) else map.putDouble(key, value)
|
|
352
443
|
}
|
|
@@ -367,6 +458,16 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
367
458
|
else -> StationaryMode.Pause
|
|
368
459
|
}
|
|
369
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
|
+
|
|
370
471
|
private fun stopReasonToWire(r: StopReason): String = when (r) {
|
|
371
472
|
StopReason.User -> "user"
|
|
372
473
|
StopReason.PermissionDenied -> "permissionDenied"
|
|
@@ -419,6 +520,11 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
419
520
|
private fun errorCode(t: Throwable): String = when (t) {
|
|
420
521
|
is BeekonException.StorageException -> "STORAGE_FAILURE"
|
|
421
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
|
+
}
|
|
422
528
|
else -> "INTERNAL_ERROR"
|
|
423
529
|
}
|
|
424
530
|
|
package/ios/BeekonRn.mm
CHANGED
|
@@ -29,6 +29,9 @@
|
|
|
29
29
|
}
|
|
30
30
|
onSyncStatus:^(NSDictionary *_Nonnull st) {
|
|
31
31
|
[weakSelf emitOnSyncStatus:st];
|
|
32
|
+
}
|
|
33
|
+
onAuthTokens:^(NSDictionary *_Nonnull t) {
|
|
34
|
+
[weakSelf emitOnAuthTokens:t];
|
|
32
35
|
}];
|
|
33
36
|
}
|
|
34
37
|
return self;
|
|
@@ -72,6 +75,16 @@
|
|
|
72
75
|
[_impl resumeIfNeededWithResolver:resolve rejecter:reject];
|
|
73
76
|
}
|
|
74
77
|
|
|
78
|
+
- (void)getCurrentLocation:(double)timeoutMs
|
|
79
|
+
accuracy:(NSString *)accuracy
|
|
80
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
81
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
82
|
+
[_impl getCurrentLocationTimeoutMs:timeoutMs
|
|
83
|
+
accuracy:accuracy
|
|
84
|
+
resolver:resolve
|
|
85
|
+
rejecter:reject];
|
|
86
|
+
}
|
|
87
|
+
|
|
75
88
|
// MARK: - History
|
|
76
89
|
|
|
77
90
|
- (void)getLocations:(double)fromMs
|
package/ios/BeekonRn.swift
CHANGED
|
@@ -22,22 +22,26 @@ import BeekonKit
|
|
|
22
22
|
private let onLocationCb: (NSDictionary) -> Void
|
|
23
23
|
private let onGeofenceEventCb: (NSDictionary) -> Void
|
|
24
24
|
private let onSyncStatusCb: (NSDictionary) -> Void
|
|
25
|
+
private let onAuthTokensCb: (NSDictionary) -> Void
|
|
25
26
|
|
|
26
27
|
private var stateTask: Task<Void, Never>?
|
|
27
28
|
private var locationsTask: Task<Void, Never>?
|
|
28
29
|
private var geofenceEventsTask: Task<Void, Never>?
|
|
29
30
|
private var syncStatusTask: Task<Void, Never>?
|
|
31
|
+
private var authTokensTask: Task<Void, Never>?
|
|
30
32
|
|
|
31
33
|
@objc public init(
|
|
32
34
|
onState: @escaping (NSDictionary) -> Void,
|
|
33
35
|
onLocation: @escaping (NSDictionary) -> Void,
|
|
34
36
|
onGeofenceEvent: @escaping (NSDictionary) -> Void,
|
|
35
|
-
onSyncStatus: @escaping (NSDictionary) -> Void
|
|
37
|
+
onSyncStatus: @escaping (NSDictionary) -> Void,
|
|
38
|
+
onAuthTokens: @escaping (NSDictionary) -> Void
|
|
36
39
|
) {
|
|
37
40
|
self.onStateCb = onState
|
|
38
41
|
self.onLocationCb = onLocation
|
|
39
42
|
self.onGeofenceEventCb = onGeofenceEvent
|
|
40
43
|
self.onSyncStatusCb = onSyncStatus
|
|
44
|
+
self.onAuthTokensCb = onAuthTokens
|
|
41
45
|
super.init()
|
|
42
46
|
self.stateTask = Task { [weak self] in
|
|
43
47
|
guard let self = self else { return }
|
|
@@ -63,6 +67,12 @@ import BeekonKit
|
|
|
63
67
|
self.onSyncStatusCb(self.syncStatusToWire(status))
|
|
64
68
|
}
|
|
65
69
|
}
|
|
70
|
+
self.authTokensTask = Task { [weak self] in
|
|
71
|
+
guard let self = self else { return }
|
|
72
|
+
for await tokens in await Beekon.shared.authChanges {
|
|
73
|
+
self.onAuthTokensCb(self.authTokensToWire(tokens))
|
|
74
|
+
}
|
|
75
|
+
}
|
|
66
76
|
}
|
|
67
77
|
|
|
68
78
|
@objc public func invalidate() {
|
|
@@ -70,10 +80,12 @@ import BeekonKit
|
|
|
70
80
|
locationsTask?.cancel()
|
|
71
81
|
geofenceEventsTask?.cancel()
|
|
72
82
|
syncStatusTask?.cancel()
|
|
83
|
+
authTokensTask?.cancel()
|
|
73
84
|
stateTask = nil
|
|
74
85
|
locationsTask = nil
|
|
75
86
|
geofenceEventsTask = nil
|
|
76
87
|
syncStatusTask = nil
|
|
88
|
+
authTokensTask = nil
|
|
77
89
|
}
|
|
78
90
|
|
|
79
91
|
/// Register Beekon's background-refresh task and install cold-launch hooks.
|
|
@@ -132,6 +144,29 @@ import BeekonKit
|
|
|
132
144
|
}
|
|
133
145
|
}
|
|
134
146
|
|
|
147
|
+
@objc public func getCurrentLocationTimeoutMs(
|
|
148
|
+
_ timeoutMs: Double,
|
|
149
|
+
accuracy: String,
|
|
150
|
+
resolver resolve: @escaping @Sendable (Any?) -> Void,
|
|
151
|
+
rejecter reject: @escaping @Sendable (String?, String?, Error?) -> Void
|
|
152
|
+
) {
|
|
153
|
+
// Empty accuracy is the wire encoding of "use the configured mode".
|
|
154
|
+
let mode: AccuracyMode? = accuracy.isEmpty ? nil : accuracyModeFromWire(accuracy)
|
|
155
|
+
Task { [weak self] in
|
|
156
|
+
guard let self = self else { return }
|
|
157
|
+
do {
|
|
158
|
+
let location = try await Beekon.shared.getCurrentLocation(
|
|
159
|
+
timeout: timeoutMs / 1000.0,
|
|
160
|
+
accuracy: mode
|
|
161
|
+
)
|
|
162
|
+
// 0- or 1-element array — empty means timeout / no fix.
|
|
163
|
+
resolve(location.map { [self.locationToWire($0)] } ?? [])
|
|
164
|
+
} catch {
|
|
165
|
+
reject(self.errorCode(error), error.localizedDescription, error)
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
|
|
135
170
|
// MARK: - History
|
|
136
171
|
|
|
137
172
|
@objc public func getLocationsFromMs(
|
|
@@ -266,14 +301,21 @@ import BeekonKit
|
|
|
266
301
|
|
|
267
302
|
var sync: SyncConfig?
|
|
268
303
|
if let s = d["sync"] as? NSDictionary,
|
|
269
|
-
let urlStr = s["url"] as? String
|
|
270
|
-
let url = URL(string: urlStr) {
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
304
|
+
let urlStr = s["url"] as? String {
|
|
305
|
+
if let url = URL(string: urlStr) {
|
|
306
|
+
let auth = (s["auth"] as? NSDictionary).map { wireToAuthConfig($0) }
|
|
307
|
+
sync = SyncConfig(
|
|
308
|
+
url: url,
|
|
309
|
+
headers: entriesToDict((s["headers"] as? NSArray) ?? []),
|
|
310
|
+
intervalSeconds: (s["intervalSeconds"] as? NSNumber)?.doubleValue ?? 300,
|
|
311
|
+
batchSize: (s["batchSize"] as? NSNumber)?.intValue ?? 100,
|
|
312
|
+
auth: auth
|
|
313
|
+
)
|
|
314
|
+
} else {
|
|
315
|
+
// Don't silently drop the whole sync config on an unparseable URL —
|
|
316
|
+
// surface it so a malformed endpoint is diagnosable instead of a no-op.
|
|
317
|
+
NSLog("[BeekonRn] sync config ignored: url is not a valid URL: %@", urlStr)
|
|
318
|
+
}
|
|
277
319
|
}
|
|
278
320
|
|
|
279
321
|
// `notification` is Android-only — iOS ignores it.
|
|
@@ -321,6 +363,35 @@ import BeekonKit
|
|
|
321
363
|
return out
|
|
322
364
|
}
|
|
323
365
|
|
|
366
|
+
private func wireToAuthConfig(_ d: NSDictionary) -> AuthConfig {
|
|
367
|
+
// Wire carries epoch millis; the native recipe wants epoch seconds.
|
|
368
|
+
let expiresAt = (d["expiresAtMs"] as? NSNumber).map { $0.doubleValue / 1000.0 }
|
|
369
|
+
let responseMapping = (d["responseMapping"] as? NSDictionary)
|
|
370
|
+
.map { wireToResponseMapping($0) } ?? AuthResponseMapping()
|
|
371
|
+
return AuthConfig(
|
|
372
|
+
accessToken: d["accessToken"] as? String,
|
|
373
|
+
refreshToken: d["refreshToken"] as? String,
|
|
374
|
+
expiresAt: expiresAt,
|
|
375
|
+
strategy: authStrategyFromWire(d["strategy"] as? String),
|
|
376
|
+
refreshUrl: (d["refreshUrl"] as? String).flatMap { URL(string: $0) },
|
|
377
|
+
refreshPayload: entriesToDict((d["refreshPayload"] as? NSArray) ?? []),
|
|
378
|
+
refreshHeaders: entriesToDict((d["refreshHeaders"] as? NSArray) ?? []),
|
|
379
|
+
refreshBodyFormat: authBodyFormatFromWire(d["refreshBodyFormat"] as? String),
|
|
380
|
+
responseMapping: responseMapping,
|
|
381
|
+
skewMarginSeconds: (d["skewMarginSeconds"] as? NSNumber)?.doubleValue ?? 60,
|
|
382
|
+
seedEpoch: (d["seedEpoch"] as? NSNumber)?.intValue
|
|
383
|
+
)
|
|
384
|
+
}
|
|
385
|
+
|
|
386
|
+
private func wireToResponseMapping(_ d: NSDictionary) -> AuthResponseMapping {
|
|
387
|
+
return AuthResponseMapping(
|
|
388
|
+
accessToken: d["accessToken"] as? String,
|
|
389
|
+
refreshToken: d["refreshToken"] as? String,
|
|
390
|
+
expiresIn: d["expiresIn"] as? String,
|
|
391
|
+
expiresAt: d["expiresAt"] as? String
|
|
392
|
+
)
|
|
393
|
+
}
|
|
394
|
+
|
|
324
395
|
// MARK: - Mappers: Beekon → wire (NSDictionary)
|
|
325
396
|
|
|
326
397
|
private func locationToWire(_ loc: Location) -> NSDictionary {
|
|
@@ -390,6 +461,18 @@ import BeekonKit
|
|
|
390
461
|
}
|
|
391
462
|
}
|
|
392
463
|
|
|
464
|
+
private func authTokensToWire(_ t: AuthTokens) -> NSDictionary {
|
|
465
|
+
// NSDictionary literals can't carry `nil`; optionals collapse to `NSNull`,
|
|
466
|
+
// which the Codegen layer translates back to `null` on the JS side.
|
|
467
|
+
let d = NSMutableDictionary()
|
|
468
|
+
d["accessToken"] = t.accessToken
|
|
469
|
+
d["refreshToken"] = t.refreshToken.map { $0 as Any } ?? NSNull()
|
|
470
|
+
// Native epoch seconds → wire epoch millis.
|
|
471
|
+
d["expiresAtMs"] = t.expiresAt.map { ($0 * 1000.0) as Any } ?? NSNull()
|
|
472
|
+
d["epoch"] = t.epoch
|
|
473
|
+
return d
|
|
474
|
+
}
|
|
475
|
+
|
|
393
476
|
// MARK: - Enum mappers
|
|
394
477
|
|
|
395
478
|
private func accuracyModeFromWire(_ s: String?) -> AccuracyMode {
|
|
@@ -408,6 +491,20 @@ import BeekonKit
|
|
|
408
491
|
}
|
|
409
492
|
}
|
|
410
493
|
|
|
494
|
+
private func authStrategyFromWire(_ s: String?) -> AuthStrategy {
|
|
495
|
+
switch s {
|
|
496
|
+
case "raw": return .raw
|
|
497
|
+
default: return .bearer
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
private func authBodyFormatFromWire(_ s: String?) -> AuthBodyFormat {
|
|
502
|
+
switch s {
|
|
503
|
+
case "json": return .json
|
|
504
|
+
default: return .form
|
|
505
|
+
}
|
|
506
|
+
}
|
|
507
|
+
|
|
411
508
|
private func stopReasonToWire(_ r: StopReason) -> String {
|
|
412
509
|
switch r {
|
|
413
510
|
case .user: return "user"
|
|
@@ -483,6 +580,13 @@ import BeekonKit
|
|
|
483
580
|
switch be {
|
|
484
581
|
case .storage: return "STORAGE_FAILURE"
|
|
485
582
|
case .invalidGeofence: return "INVALID_GEOFENCE"
|
|
583
|
+
case .locationUnavailable(let reason):
|
|
584
|
+
switch reason {
|
|
585
|
+
case .permissionDenied: return "PERMISSION_DENIED"
|
|
586
|
+
case .locationServicesDisabled: return "LOCATION_SERVICES_DISABLED"
|
|
587
|
+
case .unavailable: return "LOCATION_UNAVAILABLE"
|
|
588
|
+
@unknown default: return "LOCATION_UNAVAILABLE"
|
|
589
|
+
}
|
|
486
590
|
@unknown default: return "INTERNAL_ERROR"
|
|
487
591
|
}
|
|
488
592
|
}
|
|
@@ -8,32 +8,32 @@
|
|
|
8
8
|
<key>BinaryPath</key>
|
|
9
9
|
<string>BeekonKit.framework/BeekonKit</string>
|
|
10
10
|
<key>LibraryIdentifier</key>
|
|
11
|
-
<string>ios-
|
|
11
|
+
<string>ios-arm64</string>
|
|
12
12
|
<key>LibraryPath</key>
|
|
13
13
|
<string>BeekonKit.framework</string>
|
|
14
14
|
<key>SupportedArchitectures</key>
|
|
15
15
|
<array>
|
|
16
16
|
<string>arm64</string>
|
|
17
|
-
<string>x86_64</string>
|
|
18
17
|
</array>
|
|
19
18
|
<key>SupportedPlatform</key>
|
|
20
19
|
<string>ios</string>
|
|
21
|
-
<key>SupportedPlatformVariant</key>
|
|
22
|
-
<string>simulator</string>
|
|
23
20
|
</dict>
|
|
24
21
|
<dict>
|
|
25
22
|
<key>BinaryPath</key>
|
|
26
23
|
<string>BeekonKit.framework/BeekonKit</string>
|
|
27
24
|
<key>LibraryIdentifier</key>
|
|
28
|
-
<string>ios-
|
|
25
|
+
<string>ios-arm64_x86_64-simulator</string>
|
|
29
26
|
<key>LibraryPath</key>
|
|
30
27
|
<string>BeekonKit.framework</string>
|
|
31
28
|
<key>SupportedArchitectures</key>
|
|
32
29
|
<array>
|
|
33
30
|
<string>arm64</string>
|
|
31
|
+
<string>x86_64</string>
|
|
34
32
|
</array>
|
|
35
33
|
<key>SupportedPlatform</key>
|
|
36
34
|
<string>ios</string>
|
|
35
|
+
<key>SupportedPlatformVariant</key>
|
|
36
|
+
<string>simulator</string>
|
|
37
37
|
</dict>
|
|
38
38
|
</array>
|
|
39
39
|
<key>CFBundlePackageType</key>
|
|
Binary file
|