@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.
- package/BeekonRn.podspec +4 -4
- package/README.md +94 -48
- package/android/build.gradle +11 -6
- package/android/src/main/java/in/wayq/beekonrn/BeekonRnModule.kt +428 -0
- package/android/src/main/java/{com → in}/wayq/beekonrn/BeekonRnPackage.kt +1 -1
- package/ios/BeekonRn.h +5 -1
- package/ios/BeekonRn.mm +90 -34
- package/ios/BeekonRn.swift +396 -116
- 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 +8636 -0
- 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 +236 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/PrivacyInfo.xcprivacy +1 -1
- 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 +8636 -0
- 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 +236 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.abi.json +8636 -0
- 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 +236 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/PrivacyInfo.xcprivacy +1 -1
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/_CodeSignature/CodeResources +2 -14
- package/lib/module/NativeBeekonRn.js +22 -7
- package/lib/module/NativeBeekonRn.js.map +1 -1
- package/lib/module/beekon.js +209 -60
- package/lib/module/beekon.js.map +1 -1
- package/lib/module/index.js +1 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal/mappers.js +145 -23
- package/lib/module/internal/mappers.js.map +1 -1
- package/lib/module/types/enums.js +2 -0
- package/lib/module/types/{preset.js.map → enums.js.map} +1 -1
- package/lib/module/types/error.js +25 -0
- package/lib/module/types/error.js.map +1 -0
- package/lib/module/types/geofence.js +2 -0
- package/lib/module/types/{position.js.map → geofence.js.map} +1 -1
- package/lib/module/types/location.js +4 -0
- package/lib/module/types/location.js.map +1 -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 +113 -35
- package/lib/typescript/src/NativeBeekonRn.d.ts.map +1 -1
- package/lib/typescript/src/beekon.d.ts +84 -49
- package/lib/typescript/src/beekon.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +7 -4
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/internal/mappers.d.ts +16 -3
- package/lib/typescript/src/internal/mappers.d.ts.map +1 -1
- package/lib/typescript/src/types/config.d.ts +53 -31
- package/lib/typescript/src/types/config.d.ts.map +1 -1
- package/lib/typescript/src/types/enums.d.ts +48 -0
- package/lib/typescript/src/types/enums.d.ts.map +1 -0
- package/lib/typescript/src/types/error.d.ts +20 -0
- package/lib/typescript/src/types/error.d.ts.map +1 -0
- 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 +40 -0
- package/lib/typescript/src/types/location.d.ts.map +1 -0
- package/lib/typescript/src/types/state.d.ts +18 -9
- 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 +5 -6
- package/scripts/fetch-beekonkit.sh +5 -2
- package/src/NativeBeekonRn.ts +120 -34
- package/src/beekon.ts +235 -63
- package/src/index.tsx +23 -4
- package/src/internal/mappers.ts +213 -22
- package/src/types/config.ts +54 -31
- package/src/types/enums.ts +64 -0
- package/src/types/error.ts +25 -0
- package/src/types/geofence.ts +37 -0
- package/src/types/location.ts +45 -0
- package/src/types/state.ts +23 -7
- package/src/types/sync.ts +23 -0
- package/android/src/main/java/com/wayq/beekonrn/BeekonRnModule.kt +0 -233
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeDirectory +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeRequirements +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeRequirements-1 +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeResources +0 -233
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeSignature +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/_CodeSignature/CodeResources +0 -113
- package/lib/module/types/position.js +0 -2
- package/lib/module/types/preset.js +0 -2
- package/lib/typescript/src/types/position.d.ts +0 -24
- package/lib/typescript/src/types/position.d.ts.map +0 -1
- package/lib/typescript/src/types/preset.d.ts +0 -12
- package/lib/typescript/src/types/preset.d.ts.map +0 -1
- package/src/types/position.ts +0 -23
- package/src/types/preset.ts +0 -11
package/ios/BeekonRn.swift
CHANGED
|
@@ -1,209 +1,489 @@
|
|
|
1
1
|
import Foundation
|
|
2
2
|
import BeekonKit
|
|
3
3
|
|
|
4
|
-
/// Swift impl of the Beekon RN TurboModule. Bridges the actor-based native
|
|
5
|
-
///
|
|
4
|
+
/// Swift impl of the Beekon RN TurboModule. Bridges the actor-based native SDK
|
|
5
|
+
/// (`BeekonKit.Beekon.shared`) to the ObjC TurboModule conformance in
|
|
6
6
|
/// `BeekonRn.mm`. All public-facing methods take ObjC-compatible callbacks
|
|
7
|
-
/// (resolver/rejecter) and dictionaries so they can be invoked from `.mm`.
|
|
7
|
+
/// (resolver/rejecter) and dictionaries/arrays so they can be invoked from `.mm`.
|
|
8
8
|
///
|
|
9
|
-
/// Event delivery: `BeekonRn.mm` constructs this with
|
|
10
|
-
/// the codegen
|
|
11
|
-
///
|
|
12
|
-
/// during
|
|
13
|
-
|
|
9
|
+
/// Event delivery: `BeekonRn.mm` constructs this with four closures that call
|
|
10
|
+
/// the codegen `emitOnState:` / `emitOnLocation:` / `emitOnGeofenceEvent:` /
|
|
11
|
+
/// `emitOnSyncStatus:` ObjC methods; the closures are invoked from per-stream
|
|
12
|
+
/// `Task`s started during init.
|
|
13
|
+
//
|
|
14
|
+
// `@unchecked Sendable` is correct here: the four emit closures are immutable
|
|
15
|
+
// `let`s, and the stream `Task`s are mutated only from init/invalidate which run
|
|
16
|
+
// sequentially. NSObject can't be auto-Sendable and `@objc` rules out `actor`,
|
|
17
|
+
// so this is the path. Non-Sendable wire inputs (NSDictionary/NSArray) are
|
|
18
|
+
// converted to Sendable Beekon types *before* crossing into any `Task`.
|
|
19
|
+
@objc public final class BeekonRnImpl: NSObject, @unchecked Sendable {
|
|
14
20
|
|
|
15
21
|
private let onStateCb: (NSDictionary) -> Void
|
|
16
|
-
private let
|
|
22
|
+
private let onLocationCb: (NSDictionary) -> Void
|
|
23
|
+
private let onGeofenceEventCb: (NSDictionary) -> Void
|
|
24
|
+
private let onSyncStatusCb: (NSDictionary) -> Void
|
|
17
25
|
|
|
18
26
|
private var stateTask: Task<Void, Never>?
|
|
19
|
-
private var
|
|
27
|
+
private var locationsTask: Task<Void, Never>?
|
|
28
|
+
private var geofenceEventsTask: Task<Void, Never>?
|
|
29
|
+
private var syncStatusTask: Task<Void, Never>?
|
|
20
30
|
|
|
21
31
|
@objc public init(
|
|
22
32
|
onState: @escaping (NSDictionary) -> Void,
|
|
23
|
-
|
|
33
|
+
onLocation: @escaping (NSDictionary) -> Void,
|
|
34
|
+
onGeofenceEvent: @escaping (NSDictionary) -> Void,
|
|
35
|
+
onSyncStatus: @escaping (NSDictionary) -> Void
|
|
24
36
|
) {
|
|
25
37
|
self.onStateCb = onState
|
|
26
|
-
self.
|
|
38
|
+
self.onLocationCb = onLocation
|
|
39
|
+
self.onGeofenceEventCb = onGeofenceEvent
|
|
40
|
+
self.onSyncStatusCb = onSyncStatus
|
|
27
41
|
super.init()
|
|
42
|
+
self.stateTask = Task { [weak self] in
|
|
43
|
+
guard let self = self else { return }
|
|
44
|
+
for await state in await Beekon.shared.state {
|
|
45
|
+
self.onStateCb(self.stateToWire(state))
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
self.locationsTask = Task { [weak self] in
|
|
49
|
+
guard let self = self else { return }
|
|
50
|
+
for await loc in await Beekon.shared.locations {
|
|
51
|
+
self.onLocationCb(self.locationToWire(loc))
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
self.geofenceEventsTask = Task { [weak self] in
|
|
55
|
+
guard let self = self else { return }
|
|
56
|
+
for await event in await Beekon.shared.geofenceEvents {
|
|
57
|
+
self.onGeofenceEventCb(self.geofenceEventToWire(event))
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
self.syncStatusTask = Task { [weak self] in
|
|
61
|
+
guard let self = self else { return }
|
|
62
|
+
for await status in await Beekon.shared.syncStatus {
|
|
63
|
+
self.onSyncStatusCb(self.syncStatusToWire(status))
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
@objc public func invalidate() {
|
|
69
|
+
stateTask?.cancel()
|
|
70
|
+
locationsTask?.cancel()
|
|
71
|
+
geofenceEventsTask?.cancel()
|
|
72
|
+
syncStatusTask?.cancel()
|
|
73
|
+
stateTask = nil
|
|
74
|
+
locationsTask = nil
|
|
75
|
+
geofenceEventsTask = nil
|
|
76
|
+
syncStatusTask = nil
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/// Register Beekon's background-refresh task and install cold-launch hooks.
|
|
80
|
+
/// Must be called once, synchronously, during app launch (before
|
|
81
|
+
/// `didFinishLaunchingWithOptions` returns) — invoke from the host AppDelegate.
|
|
82
|
+
@objc public static func registerBackgroundTasks() {
|
|
83
|
+
Beekon.registerBackgroundTasks()
|
|
84
|
+
// Touch the shared actor so its cold-launch resume hooks install.
|
|
85
|
+
_ = Beekon.shared
|
|
28
86
|
}
|
|
29
87
|
|
|
30
88
|
// MARK: - Lifecycle
|
|
31
89
|
|
|
32
|
-
@objc public func
|
|
33
|
-
_
|
|
34
|
-
|
|
90
|
+
@objc public func configure(
|
|
91
|
+
_ config: NSDictionary,
|
|
92
|
+
resolver resolve: @escaping @Sendable (Any?) -> Void,
|
|
93
|
+
rejecter _: @escaping @Sendable (String?, String?, Error?) -> Void
|
|
94
|
+
) {
|
|
95
|
+
// Convert the non-Sendable NSDictionary to a Sendable BeekonConfig before
|
|
96
|
+
// crossing into the Task closure.
|
|
97
|
+
let cfg = wireToConfig(config)
|
|
98
|
+
Task {
|
|
99
|
+
await Beekon.shared.configure(cfg)
|
|
100
|
+
resolve(nil)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
@objc public func startWithResolver(
|
|
105
|
+
_ resolve: @escaping @Sendable (Any?) -> Void,
|
|
106
|
+
rejecter _: @escaping @Sendable (String?, String?, Error?) -> Void
|
|
107
|
+
) {
|
|
108
|
+
// start() never throws — outcome surfaces on the `state` stream.
|
|
109
|
+
Task {
|
|
110
|
+
await Beekon.shared.start()
|
|
111
|
+
resolve(nil)
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
@objc public func stopWithResolver(
|
|
116
|
+
_ resolve: @escaping @Sendable (Any?) -> Void,
|
|
117
|
+
rejecter _: @escaping @Sendable (String?, String?, Error?) -> Void
|
|
118
|
+
) {
|
|
119
|
+
Task {
|
|
120
|
+
await Beekon.shared.stop()
|
|
121
|
+
resolve(nil)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
@objc public func resumeIfNeededWithResolver(
|
|
126
|
+
_ resolve: @escaping @Sendable (Any?) -> Void,
|
|
127
|
+
rejecter _: @escaping @Sendable (String?, String?, Error?) -> Void
|
|
128
|
+
) {
|
|
129
|
+
Task {
|
|
130
|
+
await Beekon.shared.resumeIfNeeded()
|
|
131
|
+
resolve(nil)
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// MARK: - History
|
|
136
|
+
|
|
137
|
+
@objc public func getLocationsFromMs(
|
|
138
|
+
_ fromMs: Double,
|
|
139
|
+
toMs: Double,
|
|
140
|
+
resolver resolve: @escaping @Sendable (Any?) -> Void,
|
|
141
|
+
rejecter reject: @escaping @Sendable (String?, String?, Error?) -> Void
|
|
35
142
|
) {
|
|
36
143
|
Task { [weak self] in
|
|
37
144
|
guard let self = self else { return }
|
|
38
145
|
do {
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
self.
|
|
43
|
-
self.stateTask = Task { [weak self] in
|
|
44
|
-
guard let self = self else { return }
|
|
45
|
-
for await state in await Beekon.shared.state {
|
|
46
|
-
self.onStateCb(self.stateToWire(state))
|
|
47
|
-
}
|
|
48
|
-
}
|
|
49
|
-
self.positionsTask = Task { [weak self] in
|
|
50
|
-
guard let self = self else { return }
|
|
51
|
-
for await pos in await Beekon.shared.positions {
|
|
52
|
-
self.onPositionCb(self.positionToWire(pos))
|
|
53
|
-
}
|
|
54
|
-
}
|
|
55
|
-
resolve(nil)
|
|
146
|
+
let from = Date(timeIntervalSince1970: fromMs / 1000.0)
|
|
147
|
+
let to = Date(timeIntervalSince1970: toMs / 1000.0)
|
|
148
|
+
let locations = try await Beekon.shared.getLocations(from: from, to: to)
|
|
149
|
+
resolve(locations.map { self.locationToWire($0) })
|
|
56
150
|
} catch {
|
|
57
151
|
reject(self.errorCode(error), error.localizedDescription, error)
|
|
58
152
|
}
|
|
59
153
|
}
|
|
60
154
|
}
|
|
61
155
|
|
|
62
|
-
@objc public func
|
|
63
|
-
_
|
|
64
|
-
resolver resolve: @escaping
|
|
65
|
-
rejecter reject: @escaping
|
|
156
|
+
@objc public func deleteLocationsBeforeMs(
|
|
157
|
+
_ beforeMs: Double,
|
|
158
|
+
resolver resolve: @escaping @Sendable (Any?) -> Void,
|
|
159
|
+
rejecter reject: @escaping @Sendable (String?, String?, Error?) -> Void
|
|
66
160
|
) {
|
|
67
161
|
Task { [weak self] in
|
|
68
162
|
guard let self = self else { return }
|
|
69
163
|
do {
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
164
|
+
// Negative is the wire sentinel for "delete all" (no cutoff).
|
|
165
|
+
let before: Date? =
|
|
166
|
+
beforeMs < 0 ? nil : Date(timeIntervalSince1970: beforeMs / 1000.0)
|
|
167
|
+
let count = try await Beekon.shared.deleteLocations(before: before)
|
|
168
|
+
resolve(count)
|
|
73
169
|
} catch {
|
|
74
170
|
reject(self.errorCode(error), error.localizedDescription, error)
|
|
75
171
|
}
|
|
76
172
|
}
|
|
77
173
|
}
|
|
78
174
|
|
|
79
|
-
@objc public func
|
|
80
|
-
_ resolve: @escaping (Any?) -> Void,
|
|
81
|
-
rejecter reject: @escaping (String?, String?, Error?) -> Void
|
|
175
|
+
@objc public func pendingUploadCountWithResolver(
|
|
176
|
+
_ resolve: @escaping @Sendable (Any?) -> Void,
|
|
177
|
+
rejecter reject: @escaping @Sendable (String?, String?, Error?) -> Void
|
|
82
178
|
) {
|
|
83
179
|
Task { [weak self] in
|
|
84
180
|
guard let self = self else { return }
|
|
85
181
|
do {
|
|
86
|
-
try await Beekon.shared.
|
|
87
|
-
resolve(
|
|
182
|
+
let count = try await Beekon.shared.pendingUploadCount()
|
|
183
|
+
resolve(count)
|
|
88
184
|
} catch {
|
|
89
185
|
reject(self.errorCode(error), error.localizedDescription, error)
|
|
90
186
|
}
|
|
91
187
|
}
|
|
92
188
|
}
|
|
93
189
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
190
|
+
// MARK: - Sync
|
|
191
|
+
|
|
192
|
+
@objc public func syncWithResolver(
|
|
193
|
+
_ resolve: @escaping @Sendable (Any?) -> Void,
|
|
194
|
+
rejecter _: @escaping @Sendable (String?, String?, Error?) -> Void
|
|
97
195
|
) {
|
|
98
|
-
Task {
|
|
99
|
-
|
|
100
|
-
await Beekon.shared.stop()
|
|
196
|
+
Task {
|
|
197
|
+
await Beekon.shared.sync()
|
|
101
198
|
resolve(nil)
|
|
102
199
|
}
|
|
103
200
|
}
|
|
104
201
|
|
|
105
|
-
@objc public func
|
|
106
|
-
_
|
|
107
|
-
|
|
202
|
+
@objc public func setExtras(
|
|
203
|
+
_ entries: NSArray,
|
|
204
|
+
resolver resolve: @escaping @Sendable (Any?) -> Void,
|
|
205
|
+
rejecter _: @escaping @Sendable (String?, String?, Error?) -> Void
|
|
108
206
|
) {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
self.positionsTask?.cancel()
|
|
113
|
-
await Beekon.shared.shutdown()
|
|
207
|
+
let extras = entriesToDict(entries)
|
|
208
|
+
Task {
|
|
209
|
+
await Beekon.shared.setExtras(extras)
|
|
114
210
|
resolve(nil)
|
|
115
211
|
}
|
|
116
212
|
}
|
|
117
213
|
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
214
|
+
// MARK: - Geofences
|
|
215
|
+
|
|
216
|
+
@objc public func addGeofences(
|
|
217
|
+
_ geofences: NSArray,
|
|
218
|
+
resolver resolve: @escaping @Sendable (Any?) -> Void,
|
|
219
|
+
rejecter reject: @escaping @Sendable (String?, String?, Error?) -> Void
|
|
123
220
|
) {
|
|
221
|
+
let list = wireToGeofences(geofences)
|
|
124
222
|
Task { [weak self] in
|
|
125
223
|
guard let self = self else { return }
|
|
126
224
|
do {
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
let positions = try await Beekon.shared.history(from: from, to: to)
|
|
130
|
-
let arr = positions.map { self.positionToWire($0) }
|
|
131
|
-
resolve(arr)
|
|
225
|
+
try await Beekon.shared.addGeofences(list)
|
|
226
|
+
resolve(nil)
|
|
132
227
|
} catch {
|
|
133
228
|
reject(self.errorCode(error), error.localizedDescription, error)
|
|
134
229
|
}
|
|
135
230
|
}
|
|
136
231
|
}
|
|
137
232
|
|
|
138
|
-
|
|
233
|
+
@objc public func removeGeofences(
|
|
234
|
+
_ ids: NSArray,
|
|
235
|
+
resolver resolve: @escaping @Sendable (Any?) -> Void,
|
|
236
|
+
rejecter _: @escaping @Sendable (String?, String?, Error?) -> Void
|
|
237
|
+
) {
|
|
238
|
+
let list = ids.compactMap { $0 as? String }
|
|
239
|
+
Task {
|
|
240
|
+
await Beekon.shared.removeGeofences(ids: list)
|
|
241
|
+
resolve(nil)
|
|
242
|
+
}
|
|
243
|
+
}
|
|
139
244
|
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
245
|
+
@objc public func listGeofencesWithResolver(
|
|
246
|
+
_ resolve: @escaping @Sendable (Any?) -> Void,
|
|
247
|
+
rejecter _: @escaping @Sendable (String?, String?, Error?) -> Void
|
|
248
|
+
) {
|
|
249
|
+
Task { [weak self] in
|
|
250
|
+
guard let self = self else { return }
|
|
251
|
+
let geofences = await Beekon.shared.listGeofences()
|
|
252
|
+
resolve(geofences.map { self.geofenceToWire($0) })
|
|
147
253
|
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
// MARK: - Mappers: wire (NSDictionary/NSArray) → Beekon
|
|
148
257
|
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
258
|
+
private func wireToConfig(_ d: NSDictionary) -> BeekonConfig {
|
|
259
|
+
let minTime =
|
|
260
|
+
(d["minTimeBetweenLocationsSeconds"] as? NSNumber)?.doubleValue ?? 30
|
|
261
|
+
let minDist =
|
|
262
|
+
(d["minDistanceBetweenLocationsMeters"] as? NSNumber)?.doubleValue ?? 100
|
|
263
|
+
let stationaryRadius =
|
|
264
|
+
(d["stationaryRadiusMeters"] as? NSNumber)?.doubleValue ?? 5
|
|
265
|
+
let detectActivity = (d["detectActivity"] as? NSNumber)?.boolValue ?? false
|
|
266
|
+
|
|
267
|
+
var sync: SyncConfig?
|
|
268
|
+
if let s = d["sync"] as? NSDictionary,
|
|
269
|
+
let urlStr = s["url"] as? String,
|
|
270
|
+
let url = URL(string: urlStr) {
|
|
271
|
+
sync = SyncConfig(
|
|
272
|
+
url: url,
|
|
273
|
+
headers: entriesToDict((s["headers"] as? NSArray) ?? []),
|
|
274
|
+
intervalSeconds: (s["intervalSeconds"] as? NSNumber)?.doubleValue ?? 300,
|
|
275
|
+
batchSize: (s["batchSize"] as? NSNumber)?.intValue ?? 100
|
|
276
|
+
)
|
|
156
277
|
}
|
|
157
|
-
let licenseKey = d["licenseKey"] as? String
|
|
158
278
|
|
|
279
|
+
// `notification` is Android-only — iOS ignores it.
|
|
159
280
|
return BeekonConfig(
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
281
|
+
minTimeBetweenLocationsSeconds: minTime,
|
|
282
|
+
minDistanceBetweenLocationsMeters: minDist,
|
|
283
|
+
accuracyMode: accuracyModeFromWire(d["accuracyMode"] as? String),
|
|
284
|
+
whenStationary: stationaryModeFromWire(d["whenStationary"] as? String),
|
|
285
|
+
stationaryRadiusMeters: stationaryRadius,
|
|
286
|
+
detectActivity: detectActivity,
|
|
287
|
+
sync: sync
|
|
164
288
|
)
|
|
165
289
|
}
|
|
166
290
|
|
|
167
|
-
private func
|
|
291
|
+
private func wireToGeofences(_ arr: NSArray) -> [BeekonGeofence] {
|
|
292
|
+
var out: [BeekonGeofence] = []
|
|
293
|
+
for case let m as NSDictionary in arr {
|
|
294
|
+
guard
|
|
295
|
+
let id = m["id"] as? String,
|
|
296
|
+
let lat = (m["lat"] as? NSNumber)?.doubleValue,
|
|
297
|
+
let lng = (m["lng"] as? NSNumber)?.doubleValue,
|
|
298
|
+
let radius = (m["radiusMeters"] as? NSNumber)?.doubleValue
|
|
299
|
+
else { continue }
|
|
300
|
+
out.append(
|
|
301
|
+
BeekonGeofence(
|
|
302
|
+
id: id,
|
|
303
|
+
latitude: lat,
|
|
304
|
+
longitude: lng,
|
|
305
|
+
radiusMeters: radius,
|
|
306
|
+
notifyOnEntry: (m["notifyOnEntry"] as? NSNumber)?.boolValue ?? true,
|
|
307
|
+
notifyOnExit: (m["notifyOnExit"] as? NSNumber)?.boolValue ?? true
|
|
308
|
+
)
|
|
309
|
+
)
|
|
310
|
+
}
|
|
311
|
+
return out
|
|
312
|
+
}
|
|
313
|
+
|
|
314
|
+
private func entriesToDict(_ arr: NSArray) -> [String: String] {
|
|
315
|
+
var out: [String: String] = [:]
|
|
316
|
+
for case let e as NSDictionary in arr {
|
|
317
|
+
if let k = e["key"] as? String, let v = e["value"] as? String {
|
|
318
|
+
out[k] = v
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
return out
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
// MARK: - Mappers: Beekon → wire (NSDictionary)
|
|
325
|
+
|
|
326
|
+
private func locationToWire(_ loc: Location) -> NSDictionary {
|
|
327
|
+
// NSDictionary literals can't carry `nil`, so optionals collapse to
|
|
328
|
+
// `NSNull` — the JS Codegen layer translates that back to `null`.
|
|
329
|
+
let d = NSMutableDictionary()
|
|
330
|
+
d["id"] = loc.id
|
|
331
|
+
d["lat"] = loc.latitude
|
|
332
|
+
d["lng"] = loc.longitude
|
|
333
|
+
d["timestampMs"] = loc.timestamp.timeIntervalSince1970 * 1000.0
|
|
334
|
+
d["accuracy"] = loc.accuracy.map { $0 as Any } ?? NSNull()
|
|
335
|
+
d["speed"] = loc.speed.map { $0 as Any } ?? NSNull()
|
|
336
|
+
d["bearing"] = loc.bearing.map { $0 as Any } ?? NSNull()
|
|
337
|
+
d["altitude"] = loc.altitude.map { $0 as Any } ?? NSNull()
|
|
338
|
+
d["quality"] = qualityToWire(loc.quality)
|
|
339
|
+
d["trigger"] = triggerToWire(loc.trigger)
|
|
340
|
+
d["motion"] = motionToWire(loc.motion)
|
|
341
|
+
d["activity"] = loc.activity.map { activityToWire($0) as Any } ?? NSNull()
|
|
342
|
+
d["isMock"] = loc.isMock
|
|
343
|
+
return d
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
private func geofenceToWire(_ g: BeekonGeofence) -> NSDictionary {
|
|
168
347
|
return [
|
|
169
|
-
"
|
|
170
|
-
"
|
|
171
|
-
"
|
|
172
|
-
"
|
|
173
|
-
"
|
|
174
|
-
"
|
|
175
|
-
|
|
348
|
+
"id": g.id,
|
|
349
|
+
"lat": g.latitude,
|
|
350
|
+
"lng": g.longitude,
|
|
351
|
+
"radiusMeters": g.radiusMeters,
|
|
352
|
+
"notifyOnEntry": g.notifyOnEntry,
|
|
353
|
+
"notifyOnExit": g.notifyOnExit,
|
|
354
|
+
]
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
private func geofenceEventToWire(_ e: GeofenceEvent) -> NSDictionary {
|
|
358
|
+
return [
|
|
359
|
+
"id": e.id,
|
|
360
|
+
"geofenceId": e.geofenceId,
|
|
361
|
+
"type": transitionToWire(e.type),
|
|
362
|
+
"timestampMs": e.timestamp.timeIntervalSince1970 * 1000.0,
|
|
176
363
|
]
|
|
177
364
|
}
|
|
178
365
|
|
|
179
366
|
private func stateToWire(_ s: BeekonState) -> NSDictionary {
|
|
180
367
|
switch s {
|
|
181
|
-
case .idle:
|
|
182
|
-
|
|
183
|
-
case .tracking:
|
|
184
|
-
|
|
185
|
-
case .
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
368
|
+
case .idle:
|
|
369
|
+
return ["type": "idle"]
|
|
370
|
+
case .tracking:
|
|
371
|
+
return ["type": "tracking"]
|
|
372
|
+
case .stopped(let reason):
|
|
373
|
+
return ["type": "stopped", "stopReason": stopReasonToWire(reason)]
|
|
374
|
+
// BeekonKit enums are non-frozen (library-evolution binary); handle unknowns.
|
|
375
|
+
@unknown default:
|
|
376
|
+
return ["type": "idle"]
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
|
|
380
|
+
private func syncStatusToWire(_ s: SyncStatus) -> NSDictionary {
|
|
381
|
+
switch s {
|
|
382
|
+
case .idle:
|
|
383
|
+
return ["type": "idle"]
|
|
384
|
+
case .pending:
|
|
385
|
+
return ["type": "pending"]
|
|
386
|
+
case .failed(let reason):
|
|
387
|
+
return ["type": "failed", "failure": syncFailureToWire(reason)]
|
|
388
|
+
@unknown default:
|
|
389
|
+
return ["type": "idle"]
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
// MARK: - Enum mappers
|
|
394
|
+
|
|
395
|
+
private func accuracyModeFromWire(_ s: String?) -> AccuracyMode {
|
|
396
|
+
switch s {
|
|
397
|
+
case "high": return .high
|
|
398
|
+
case "low": return .low
|
|
399
|
+
default: return .balanced
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
private func stationaryModeFromWire(_ s: String?) -> StationaryMode {
|
|
404
|
+
switch s {
|
|
405
|
+
case "keepTracking": return .keepTracking
|
|
406
|
+
case "pauseWithCheckIns": return .pauseWithCheckIns
|
|
407
|
+
default: return .pause
|
|
408
|
+
}
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
private func stopReasonToWire(_ r: StopReason) -> String {
|
|
412
|
+
switch r {
|
|
413
|
+
case .user: return "user"
|
|
414
|
+
case .permissionDenied: return "permissionDenied"
|
|
415
|
+
case .locationServicesDisabled: return "locationServicesDisabled"
|
|
416
|
+
case .locationUnavailable: return "locationUnavailable"
|
|
417
|
+
case .system: return "system"
|
|
418
|
+
@unknown default: return "system"
|
|
419
|
+
}
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
private func syncFailureToWire(_ f: SyncFailure) -> String {
|
|
423
|
+
switch f {
|
|
424
|
+
case .auth: return "auth"
|
|
425
|
+
case .rejected: return "rejected"
|
|
426
|
+
@unknown default: return "rejected"
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
private func qualityToWire(_ q: LocationQuality) -> String {
|
|
431
|
+
switch q {
|
|
432
|
+
case .ok: return "ok"
|
|
433
|
+
case .lowAccuracy: return "lowAccuracy"
|
|
434
|
+
case .implausibleSpeed: return "implausibleSpeed"
|
|
435
|
+
@unknown default: return "ok"
|
|
436
|
+
}
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
private func triggerToWire(_ t: LocationTrigger) -> String {
|
|
440
|
+
switch t {
|
|
441
|
+
case .interval: return "interval"
|
|
442
|
+
case .motion: return "motion"
|
|
443
|
+
case .checkIn: return "checkIn"
|
|
444
|
+
case .geofence: return "geofence"
|
|
445
|
+
case .manual: return "manual"
|
|
446
|
+
@unknown default: return "interval"
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
private func motionToWire(_ m: MotionState) -> String {
|
|
451
|
+
switch m {
|
|
452
|
+
case .moving: return "moving"
|
|
453
|
+
case .stationary: return "stationary"
|
|
454
|
+
case .unknown: return "unknown"
|
|
455
|
+
@unknown default: return "unknown"
|
|
456
|
+
}
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
private func activityToWire(_ a: ActivityType) -> String {
|
|
460
|
+
switch a {
|
|
461
|
+
case .stationary: return "stationary"
|
|
462
|
+
case .walking: return "walking"
|
|
463
|
+
case .running: return "running"
|
|
464
|
+
case .cycling: return "cycling"
|
|
465
|
+
case .automotive: return "automotive"
|
|
466
|
+
case .unknown: return "unknown"
|
|
467
|
+
@unknown default: return "unknown"
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
private func transitionToWire(_ t: Transition) -> String {
|
|
472
|
+
switch t {
|
|
473
|
+
case .enter: return "enter"
|
|
474
|
+
case .exit: return "exit"
|
|
475
|
+
@unknown default: return "enter"
|
|
193
476
|
}
|
|
194
477
|
}
|
|
195
478
|
|
|
196
|
-
/// Maps native `BeekonError` cases to stable string codes shared with
|
|
197
|
-
///
|
|
198
|
-
/// branches.
|
|
479
|
+
/// Maps native `BeekonError` cases to stable string codes shared with Android,
|
|
480
|
+
/// so JS-side error handling can switch on them without per-platform branches.
|
|
199
481
|
private func errorCode(_ e: Error) -> String {
|
|
200
482
|
if let be = e as? BeekonError {
|
|
201
483
|
switch be {
|
|
202
|
-
case .
|
|
203
|
-
case .
|
|
204
|
-
|
|
205
|
-
case .notInitialised: return "NOT_INITIALISED"
|
|
206
|
-
case .internalError: return "INTERNAL_ERROR"
|
|
484
|
+
case .storage: return "STORAGE_FAILURE"
|
|
485
|
+
case .invalidGeofence: return "INVALID_GEOFENCE"
|
|
486
|
+
@unknown default: return "INTERNAL_ERROR"
|
|
207
487
|
}
|
|
208
488
|
}
|
|
209
489
|
return "INTERNAL_ERROR"
|
|
Binary file
|