@wayq/beekon-rn 0.0.8 → 0.0.9
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 +1 -1
- package/CHANGELOG.md +30 -0
- package/README.md +67 -5
- package/android/build.gradle +1 -1
- package/android/src/main/java/in/wayq/beekonrn/BeekonRnModule.kt +106 -8
- package/ios/BeekonRn.mm +35 -0
- package/ios/BeekonRn.swift +140 -8
- 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 +6036 -3700
- 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 +95 -18
- 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 +6036 -3700
- 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 +95 -18
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.abi.json +6036 -3700
- 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 +95 -18
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/_CodeSignature/CodeResources +1 -1
- package/lib/module/NativeBeekonRn.js.map +1 -1
- package/lib/module/beekon.js +97 -1
- package/lib/module/beekon.js.map +1 -1
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal/licenseNudge.js +64 -0
- package/lib/module/internal/licenseNudge.js.map +1 -0
- package/lib/module/internal/mappers.js +56 -8
- package/lib/module/internal/mappers.js.map +1 -1
- package/lib/module/types/config.js +73 -1
- package/lib/module/types/config.js.map +1 -1
- package/lib/module/types/log.js +4 -0
- package/lib/module/types/log.js.map +1 -0
- package/lib/typescript/src/NativeBeekonRn.d.ts +47 -2
- package/lib/typescript/src/NativeBeekonRn.d.ts.map +1 -1
- package/lib/typescript/src/beekon.d.ts +46 -1
- package/lib/typescript/src/beekon.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +4 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/internal/licenseNudge.d.ts +38 -0
- package/lib/typescript/src/internal/licenseNudge.d.ts.map +1 -0
- package/lib/typescript/src/internal/mappers.d.ts +3 -1
- package/lib/typescript/src/internal/mappers.d.ts.map +1 -1
- package/lib/typescript/src/types/config.d.ts +90 -7
- package/lib/typescript/src/types/config.d.ts.map +1 -1
- package/lib/typescript/src/types/enums.d.ts +8 -0
- package/lib/typescript/src/types/enums.d.ts.map +1 -1
- package/lib/typescript/src/types/log.d.ts +22 -0
- package/lib/typescript/src/types/log.d.ts.map +1 -0
- package/lib/typescript/src/types/state.d.ts +4 -1
- package/lib/typescript/src/types/state.d.ts.map +1 -1
- package/package.json +1 -1
- package/scripts/fetch-beekonkit.sh +4 -4
- package/src/NativeBeekonRn.ts +49 -2
- package/src/beekon.ts +100 -1
- package/src/index.tsx +7 -1
- package/src/internal/licenseNudge.ts +80 -0
- package/src/internal/mappers.ts +67 -7
- package/src/types/config.ts +99 -7
- package/src/types/enums.ts +9 -0
- package/src/types/log.ts +22 -0
- package/src/types/state.ts +4 -0
package/BeekonRn.podspec
CHANGED
|
@@ -11,7 +11,7 @@ Pod::Spec.new do |s|
|
|
|
11
11
|
s.authors = package["author"]
|
|
12
12
|
|
|
13
13
|
# iOS 17.0 floor reflects this wrapper's React Native baseline (RN 0.85), not
|
|
14
|
-
# a BeekonKit constraint — BeekonKit 0.0.
|
|
14
|
+
# a BeekonKit constraint — BeekonKit 0.0.9 itself supports iOS 13+ (with
|
|
15
15
|
# 13–16 fallback paths). Kept at 17.0 to avoid any consumer regression; do not
|
|
16
16
|
# lower below React Native's own minimum.
|
|
17
17
|
s.platforms = { :ios => "17.0" }
|
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,36 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
Beekon is pre-1.0 — releases may contain breaking changes.
|
|
8
8
|
|
|
9
|
+
## [0.0.9] - 2026-06-14
|
|
10
|
+
|
|
11
|
+
### Added
|
|
12
|
+
|
|
13
|
+
- **Cloud mode** (cloud-mode-v1): point a project key (`bkproj_…`) at Beekon
|
|
14
|
+
Cloud and let the server own tracking config, geofences, and the license.
|
|
15
|
+
Built via `BeekonConfig.cloud(...)`; cloud config takes the project key and an
|
|
16
|
+
optional `endpoint` (default `https://api.getbeekon.com`). Requires the native
|
|
17
|
+
SDKs ≥ 0.0.9.
|
|
18
|
+
- **Diagnostic logging** (log-format-v1): `getLog` / `exportLog` / `clearLog` /
|
|
19
|
+
`setLogLevel` / `log` plus the `onLog` subscription and `LogEntry` / `LogLevel`
|
|
20
|
+
types; `logLevel` on each config arm sets the threshold. Requires the native
|
|
21
|
+
SDKs ≥ 0.0.9.
|
|
22
|
+
- **`SyncConfig.syncThreshold`** ([beekon#20]): pending-fix count that triggers
|
|
23
|
+
an early upload of regular fixes ahead of the `intervalSeconds` schedule (not
|
|
24
|
+
subject to the Android ~15 min WorkManager floor). `0` (the default) leaves
|
|
25
|
+
regular fixes to the schedule. Independent of this setting, a geofence event
|
|
26
|
+
and a session stop with pending fixes always flush immediately while sync is
|
|
27
|
+
configured. Requires the native SDKs ≥ 0.0.9.
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
|
|
31
|
+
- **BREAKING:** `BeekonConfig` is now a sealed two-arm discriminated union
|
|
32
|
+
(`CloudConfig | SelfManagedConfig`) built via `BeekonConfig.cloud(...)` /
|
|
33
|
+
`BeekonConfig.selfManaged(...)`; the flat config object is gone and a `mode`
|
|
34
|
+
discriminator (`'cloud'` | `'selfManaged'`) is now required. Tracking params,
|
|
35
|
+
`sync`, and `licenseKey` live only on the `selfManaged` arm.
|
|
36
|
+
|
|
37
|
+
[beekon#20]: https://github.com/wayqteam/beekon/issues/20
|
|
38
|
+
|
|
9
39
|
## [0.0.8]
|
|
10
40
|
|
|
11
41
|
Built against the native **0.0.8** API; requires native ≥ 0.0.8 at runtime.
|
package/README.md
CHANGED
|
@@ -33,6 +33,8 @@ Capture GPS in the foreground and background, keep a queryable history on the de
|
|
|
33
33
|
- On-device history you can query at any time
|
|
34
34
|
- Geofencing with enter and exit events
|
|
35
35
|
- Optional batched server sync with automatic retry
|
|
36
|
+
- Beekon Cloud mode: point at a project with a `bkproj_` key and let the server own tracking config, geofences, and license
|
|
37
|
+
- Diagnostic logging: query/export an on-device log buffer and stream live entries for field debugging
|
|
36
38
|
- Activity detection (walking, running, cycling, automotive)
|
|
37
39
|
- Built for the React Native New Architecture
|
|
38
40
|
|
|
@@ -133,6 +135,7 @@ const offLocation = Beekon.onLocation((location) => {
|
|
|
133
135
|
|
|
134
136
|
// Configure is optional. Request OS permissions before starting.
|
|
135
137
|
await Beekon.configure({
|
|
138
|
+
mode: 'selfManaged',
|
|
136
139
|
minTimeBetweenLocationsSeconds: 30,
|
|
137
140
|
minDistanceBetweenLocationsMeters: 100,
|
|
138
141
|
});
|
|
@@ -151,7 +154,7 @@ offLocation();
|
|
|
151
154
|
Beekon.onState((state) => {
|
|
152
155
|
if (state.kind === 'stopped') {
|
|
153
156
|
// 'user' | 'permissionDenied' | 'locationServicesDisabled'
|
|
154
|
-
// | 'locationUnavailable' | 'system'
|
|
157
|
+
// | 'locationUnavailable' | 'cloudModeUnavailable' | 'system'
|
|
155
158
|
console.log('stopped:', state.reason);
|
|
156
159
|
}
|
|
157
160
|
});
|
|
@@ -190,6 +193,7 @@ Add a `sync` config to upload recorded fixes and geofence events to your backend
|
|
|
190
193
|
|
|
191
194
|
```ts
|
|
192
195
|
await Beekon.configure({
|
|
196
|
+
mode: 'selfManaged',
|
|
193
197
|
sync: {
|
|
194
198
|
url: 'https://api.example.com/locations',
|
|
195
199
|
headers: { Authorization: 'Bearer <token>' },
|
|
@@ -212,6 +216,7 @@ The supplied tokens are a **seed**: the SDK owns and rotates the live token set
|
|
|
212
216
|
|
|
213
217
|
```ts
|
|
214
218
|
await Beekon.configure({
|
|
219
|
+
mode: 'selfManaged',
|
|
215
220
|
sync: {
|
|
216
221
|
url: 'https://api.example.com/locations',
|
|
217
222
|
auth: {
|
|
@@ -237,9 +242,33 @@ const offAuth = Beekon.onAuthTokens((tokens) => {
|
|
|
237
242
|
|
|
238
243
|
The refresh recipe is persisted in plaintext to survive a cold launch — **do not** put static client secrets in `refreshHeaders` or `refreshPayload`. Requires the native SDK ≥ 0.0.6; with an older native binary the recipe is ignored and only static `sync.headers` apply.
|
|
239
244
|
|
|
245
|
+
### License
|
|
246
|
+
|
|
247
|
+
Supply a Beekon license token (a `license-format-v1` JWS) with `licenseKey`. It is the highest-priority channel, overriding the platform manifest value (`in.wayq.beekon.license` meta-data on Android, `BeekonLicenseKey` in `Info.plist` on iOS); `undefined`, blank, or whitespace-only means unset. A token is app-id- and product-bound, so it is safe to commit to source control.
|
|
248
|
+
|
|
249
|
+
```ts
|
|
250
|
+
await Beekon.configure({
|
|
251
|
+
mode: 'selfManaged',
|
|
252
|
+
licenseKey: '<license-format-v1 JWS>',
|
|
253
|
+
});
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
The license is **purely observational** — no status ever blocks, degrades, or delays the SDK. Read the current platform's status once with `licenseStatus()`, or subscribe with `onLicenseStatus` (the latest status is delivered immediately):
|
|
257
|
+
|
|
258
|
+
```ts
|
|
259
|
+
const status = await Beekon.licenseStatus();
|
|
260
|
+
console.log('license:', status.status); // 'evaluation' | 'licensed' | ...
|
|
261
|
+
|
|
262
|
+
const offLicense = Beekon.onLicenseStatus((s) => {
|
|
263
|
+
if (s.status === 'licensed') console.log('tier:', s.tier);
|
|
264
|
+
});
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Android and iOS validate independently and may legally report different statuses for the same app (for example a license scoped to `["android"]` reads `licensed` on Android and `invalid` / `productMismatch` on iOS). The value reflects only the platform you are running on.
|
|
268
|
+
|
|
240
269
|
## Configuration
|
|
241
270
|
|
|
242
|
-
|
|
271
|
+
`BeekonConfig` is a sealed two-arm union — pass `mode: 'selfManaged'` (the options below, all optional) or `mode: 'cloud'` (`{ projectKey, endpoint?, notification?, logLevel? }`, where the server owns tracking/geofences/license). Self-managed options (defaults shown):
|
|
243
272
|
|
|
244
273
|
| Option | Default | Description |
|
|
245
274
|
|---|---|---|
|
|
@@ -249,8 +278,9 @@ All options are optional; defaults are shown.
|
|
|
249
278
|
| `whenStationary` | `'pause'` | `'keepTracking'` \| `'pause'` \| `'pauseWithCheckIns'`. |
|
|
250
279
|
| `stationaryRadiusMeters` | `5` | Distance the device must move to count as moving again. |
|
|
251
280
|
| `detectActivity` | `false` | Detect physical activity. Requires the motion permission. |
|
|
252
|
-
| `sync` | – | Server upload settings: `{ url, headers?, intervalSeconds?, batchSize?, auth? }`. See [Token refresh](#token-refresh). |
|
|
281
|
+
| `sync` | – | Server upload settings: `{ url, headers?, intervalSeconds?, batchSize?, syncThreshold?, auth? }`. See [Token refresh](#token-refresh). |
|
|
253
282
|
| `notification` | – | Android-only tracking notification: `{ title?, text?, smallIcon? }`. `smallIcon` is a drawable/mipmap resource name. |
|
|
283
|
+
| `licenseKey` | – | Beekon license token (`license-format-v1` JWS). Highest-priority supply channel; overrides the platform manifest value. See [License](#license). |
|
|
254
284
|
|
|
255
285
|
A fix is recorded only when **both** the time and distance filters are satisfied.
|
|
256
286
|
|
|
@@ -271,6 +301,12 @@ A fix is recorded only when **both** the time and distance filters are satisfied
|
|
|
271
301
|
| `addGeofences(geofences)` | Register circular regions. |
|
|
272
302
|
| `removeGeofences(ids)` | Unregister geofences by id. |
|
|
273
303
|
| `listGeofences()` | Currently registered geofences. |
|
|
304
|
+
| `licenseStatus()` | Current platform's license status (a `LicenseStatus`). Observational only. See [License](#license). |
|
|
305
|
+
| `getLog(from, to)` | Persisted diagnostic log entries in a date range (oldest first). |
|
|
306
|
+
| `exportLog()` | Serialize the log buffer to an NDJSON file; resolves the file path. |
|
|
307
|
+
| `clearLog()` | Delete all persisted diagnostic log entries. |
|
|
308
|
+
| `setLogLevel(level)` | Change the diagnostic log verbosity threshold at runtime. |
|
|
309
|
+
| `log(level, message)` | Write a host-app breadcrumb into the SDK log pipeline (category `app`). |
|
|
274
310
|
|
|
275
311
|
Subscriptions — each returns an unsubscribe function:
|
|
276
312
|
|
|
@@ -281,6 +317,8 @@ Subscriptions — each returns an unsubscribe function:
|
|
|
281
317
|
| `onGeofenceEvent(cb)` | Geofence enter and exit events. |
|
|
282
318
|
| `onSyncStatus(cb)` | Upload status. The current status is delivered immediately. |
|
|
283
319
|
| `onAuthTokens(cb)` | Token rotations from native refresh (see [Token refresh](#token-refresh)). The latest rotation is delivered immediately. |
|
|
320
|
+
| `onLicenseStatus(cb)` | License status changes (see [License](#license)). The current status is delivered immediately. |
|
|
321
|
+
| `onLog(cb)` | Diagnostic log entries as they are recorded (broadcast, no replay). |
|
|
284
322
|
|
|
285
323
|
`getLocations`, `deleteLocations`, `pendingUploadCount`, and `addGeofences` reject with a `BeekonError` on failure — check `error.kind` (`'storage'` or `'invalidGeofence'`). `getCurrentLocation` rejects with `error.kind` `'permissionDenied'`, `'locationServicesDisabled'`, or `'locationUnavailable'` on a precondition failure. Other methods resolve normally; tracking-lifecycle problems are reported through `onState` rather than thrown.
|
|
286
324
|
|
|
@@ -312,7 +350,7 @@ type BeekonState =
|
|
|
312
350
|
kind: 'stopped';
|
|
313
351
|
reason:
|
|
314
352
|
| 'user' | 'permissionDenied' | 'locationServicesDisabled'
|
|
315
|
-
| 'locationUnavailable' | 'system';
|
|
353
|
+
| 'locationUnavailable' | 'cloudModeUnavailable' | 'system';
|
|
316
354
|
};
|
|
317
355
|
|
|
318
356
|
type SyncStatus =
|
|
@@ -365,6 +403,30 @@ type AuthTokens = {
|
|
|
365
403
|
expiresAt: Date | null;
|
|
366
404
|
epoch: number; // monotonic generation, bumped on each refresh
|
|
367
405
|
};
|
|
406
|
+
|
|
407
|
+
// Returned by `licenseStatus()` / delivered by `onLicenseStatus`. Observational
|
|
408
|
+
// only — no status ever blocks the SDK. Use `status` as the discriminator.
|
|
409
|
+
type LicenseStatus =
|
|
410
|
+
| { status: 'notDetermined' }
|
|
411
|
+
| { status: 'evaluation' }
|
|
412
|
+
| { status: 'expired' }
|
|
413
|
+
| { status: 'updateEntitlementLapsed' }
|
|
414
|
+
| { status: 'licensed'; tier: string; entitlements: string[] }
|
|
415
|
+
| { status: 'invalid'; reason: LicenseInvalidReason };
|
|
416
|
+
|
|
417
|
+
type LicenseInvalidReason =
|
|
418
|
+
| 'malformed' | 'unknownKey' | 'badSignature'
|
|
419
|
+
| 'appIdMismatch' | 'productMismatch' | 'unsupportedVersion';
|
|
420
|
+
|
|
421
|
+
type LogLevel = 'off' | 'error' | 'warn' | 'info' | 'debug' | 'verbose';
|
|
422
|
+
|
|
423
|
+
type LogEntry = {
|
|
424
|
+
id: string; // UUIDv7
|
|
425
|
+
timestamp: Date;
|
|
426
|
+
level: LogLevel;
|
|
427
|
+
category: string; // e.g. 'location', 'sync'; host breadcrumbs use 'app'
|
|
428
|
+
message: string;
|
|
429
|
+
};
|
|
368
430
|
```
|
|
369
431
|
|
|
370
432
|
Optional numeric fields on `Location` are `null` when the device did not report them — never `0`.
|
|
@@ -381,7 +443,7 @@ A complete, runnable example is in the [`example/`](./example) directory.
|
|
|
381
443
|
|
|
382
444
|
## License
|
|
383
445
|
|
|
384
|
-
Proprietary — evaluation use only without a separate written agreement with
|
|
446
|
+
Proprietary — evaluation use only without a separate written agreement with WayQ Technologies Pvt Ltd. See [LICENSE.txt](./LICENSE.txt).
|
|
385
447
|
|
|
386
448
|
---
|
|
387
449
|
|
package/android/build.gradle
CHANGED
|
@@ -79,7 +79,7 @@ dependencies {
|
|
|
79
79
|
// the SDK reaches v1 stability. 0.0.7 is the release that ships the license
|
|
80
80
|
// API (setWrapperInfo / BeekonConfig.licenseKey / Beekon.licenseStatus);
|
|
81
81
|
// 0.0.8 embeds the production ES256 verification keyset.
|
|
82
|
-
implementation "io.github.wayqteam:beekon:0.0.
|
|
82
|
+
implementation "io.github.wayqteam:beekon:0.0.9"
|
|
83
83
|
// Kotlin coroutines — required for collecting Beekon's StateFlow/SharedFlow.
|
|
84
84
|
// Beekon already depends on coroutines transitively, but declaring it here
|
|
85
85
|
// makes the dependency intent explicit.
|
|
@@ -25,6 +25,8 @@ import `in`.wayq.beekon.Location
|
|
|
25
25
|
import `in`.wayq.beekon.LocationQuality
|
|
26
26
|
import `in`.wayq.beekon.LocationTrigger
|
|
27
27
|
import `in`.wayq.beekon.LocationUnavailableReason
|
|
28
|
+
import `in`.wayq.beekon.LogEntry
|
|
29
|
+
import `in`.wayq.beekon.LogLevel
|
|
28
30
|
import `in`.wayq.beekon.MotionState
|
|
29
31
|
import `in`.wayq.beekon.NotificationConfig
|
|
30
32
|
import `in`.wayq.beekon.StationaryMode
|
|
@@ -64,6 +66,7 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
64
66
|
scope.launch { Beekon.syncStatus.collect { emitOnSyncStatus(syncStatusToWire(it)) } }
|
|
65
67
|
scope.launch { Beekon.authChanges.collect { emitOnAuthTokens(tokenRefreshToWire(it)) } }
|
|
66
68
|
scope.launch { Beekon.licenseStatus.collect { emitOnLicenseStatus(licenseStatusToWire(it)) } }
|
|
69
|
+
scope.launch { Beekon.logs.collect { emitOnLog(logEntryToWire(it)) } }
|
|
67
70
|
}
|
|
68
71
|
|
|
69
72
|
// ---------------------------------------------------------------------------
|
|
@@ -232,6 +235,55 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
232
235
|
promise.resolve(licenseStatusToWire(Beekon.licenseStatus.value))
|
|
233
236
|
}
|
|
234
237
|
|
|
238
|
+
// ---------------------------------------------------------------------------
|
|
239
|
+
// Diagnostic logs (spec diagnostics/log-format-v1)
|
|
240
|
+
// ---------------------------------------------------------------------------
|
|
241
|
+
|
|
242
|
+
override fun getLog(fromMs: Double, toMs: Double, promise: Promise) {
|
|
243
|
+
scope.launch {
|
|
244
|
+
try {
|
|
245
|
+
val from = Instant.ofEpochMilli(fromMs.toLong())
|
|
246
|
+
val to = Instant.ofEpochMilli(toMs.toLong())
|
|
247
|
+
val arr: WritableArray = Arguments.createArray()
|
|
248
|
+
for (e in Beekon.getLog(from, to)) arr.pushMap(logEntryToWire(e))
|
|
249
|
+
promise.resolve(arr)
|
|
250
|
+
} catch (t: Throwable) {
|
|
251
|
+
promise.reject(errorCode(t), t.message ?: "getLog failed", t)
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
override fun exportLog(promise: Promise) {
|
|
257
|
+
scope.launch {
|
|
258
|
+
try {
|
|
259
|
+
promise.resolve(Beekon.exportLog())
|
|
260
|
+
} catch (t: Throwable) {
|
|
261
|
+
promise.reject(errorCode(t), t.message ?: "exportLog failed", t)
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
override fun clearLog(promise: Promise) {
|
|
267
|
+
scope.launch {
|
|
268
|
+
try {
|
|
269
|
+
Beekon.clearLog()
|
|
270
|
+
promise.resolve(null)
|
|
271
|
+
} catch (t: Throwable) {
|
|
272
|
+
promise.reject(errorCode(t), t.message ?: "clearLog failed", t)
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
override fun setLogLevel(level: String, promise: Promise) {
|
|
278
|
+
Beekon.setLogLevel(toLogLevel(level))
|
|
279
|
+
promise.resolve(null)
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
override fun log(level: String, message: String, promise: Promise) {
|
|
283
|
+
Beekon.log(toLogLevel(level), message)
|
|
284
|
+
promise.resolve(null)
|
|
285
|
+
}
|
|
286
|
+
|
|
235
287
|
override fun invalidate() {
|
|
236
288
|
super.invalidate()
|
|
237
289
|
scope.cancel()
|
|
@@ -241,20 +293,47 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
241
293
|
// Mappers: wire (ReadableMap/Array) → Kotlin
|
|
242
294
|
// ---------------------------------------------------------------------------
|
|
243
295
|
|
|
296
|
+
// GATED on beekon native 0.0.9 (sealed BeekonConfig) — does not compile against
|
|
297
|
+
// the pinned 0.0.8 dep (the flat BeekonConfig(...) constructor). Switches on the
|
|
298
|
+
// wire `mode` (cloud-mode-v1 §2) to build the matching sealed arm. A cloud
|
|
299
|
+
// configuration with an empty/invalid projectKey throws
|
|
300
|
+
// BeekonException.InvalidConfiguration, which the configure() catch turns into a
|
|
301
|
+
// promise rejection via errorCode().
|
|
244
302
|
private fun wireToConfig(map: ReadableMap): BeekonConfig {
|
|
245
|
-
val sync =
|
|
246
|
-
if (map.hasKey("sync") && !map.isNull("sync")) {
|
|
247
|
-
map.getMap("sync")?.let { wireToSyncConfig(it) }
|
|
248
|
-
} else {
|
|
249
|
-
null
|
|
250
|
-
}
|
|
251
303
|
val notification =
|
|
252
304
|
if (map.hasKey("notification") && !map.isNull("notification")) {
|
|
253
305
|
map.getMap("notification")?.let { wireToNotification(it) }
|
|
254
306
|
} else {
|
|
255
307
|
null
|
|
256
308
|
}
|
|
257
|
-
|
|
309
|
+
|
|
310
|
+
if (optString(map, "mode") == "cloud") {
|
|
311
|
+
val projectKey = optString(map, "projectKey") ?: ""
|
|
312
|
+
val endpoint = optString(map, "endpoint")
|
|
313
|
+
// Omitted endpoint → fall back to the constructor's baked-in default.
|
|
314
|
+
return if (endpoint != null) {
|
|
315
|
+
BeekonConfig.Cloud(
|
|
316
|
+
projectKey = projectKey,
|
|
317
|
+
endpoint = endpoint,
|
|
318
|
+
notification = notification ?: NotificationConfig(),
|
|
319
|
+
logLevel = toLogLevel(optString(map, "logLevel")),
|
|
320
|
+
)
|
|
321
|
+
} else {
|
|
322
|
+
BeekonConfig.Cloud(
|
|
323
|
+
projectKey = projectKey,
|
|
324
|
+
notification = notification ?: NotificationConfig(),
|
|
325
|
+
logLevel = toLogLevel(optString(map, "logLevel")),
|
|
326
|
+
)
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
val sync =
|
|
331
|
+
if (map.hasKey("sync") && !map.isNull("sync")) {
|
|
332
|
+
map.getMap("sync")?.let { wireToSyncConfig(it) }
|
|
333
|
+
} else {
|
|
334
|
+
null
|
|
335
|
+
}
|
|
336
|
+
return BeekonConfig.SelfManaged(
|
|
258
337
|
minTimeBetweenLocationsSeconds =
|
|
259
338
|
map.getDouble("minTimeBetweenLocationsSeconds").toLong(),
|
|
260
339
|
minDistanceBetweenLocationsMeters =
|
|
@@ -268,6 +347,7 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
268
347
|
// Passed through verbatim; absent/null means unset — the SDK falls through
|
|
269
348
|
// to the manifest meta-data, then evaluation (license-format-v1 §9).
|
|
270
349
|
licenseKey = optString(map, "licenseKey"),
|
|
350
|
+
logLevel = toLogLevel(optString(map, "logLevel")),
|
|
271
351
|
)
|
|
272
352
|
}
|
|
273
353
|
|
|
@@ -283,6 +363,7 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
283
363
|
headers = entriesToMap(map.getArray("headers")),
|
|
284
364
|
intervalSeconds = map.getDouble("intervalSeconds").toLong(),
|
|
285
365
|
batchSize = map.getDouble("batchSize").toInt(),
|
|
366
|
+
syncThreshold = if (map.hasKey("syncThreshold")) map.getDouble("syncThreshold").toInt() else 0,
|
|
286
367
|
auth = auth,
|
|
287
368
|
)
|
|
288
369
|
}
|
|
@@ -484,6 +565,16 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
484
565
|
return m
|
|
485
566
|
}
|
|
486
567
|
|
|
568
|
+
private fun logEntryToWire(e: LogEntry): WritableMap {
|
|
569
|
+
val m = Arguments.createMap()
|
|
570
|
+
m.putString("id", e.id)
|
|
571
|
+
m.putDouble("timestampMs", e.timestamp.toEpochMilli().toDouble())
|
|
572
|
+
m.putString("level", e.level.wire)
|
|
573
|
+
m.putString("category", e.category)
|
|
574
|
+
m.putString("message", e.message)
|
|
575
|
+
return m
|
|
576
|
+
}
|
|
577
|
+
|
|
487
578
|
private fun putNullableDouble(map: WritableMap, key: String, value: Double?) {
|
|
488
579
|
if (value == null) map.putNull(key) else map.putDouble(key, value)
|
|
489
580
|
}
|
|
@@ -514,11 +605,18 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
514
605
|
else -> AuthBodyFormat.Form
|
|
515
606
|
}
|
|
516
607
|
|
|
608
|
+
// Wire token (lowercase) -> native LogLevel; unknown/absent defaults to Info.
|
|
609
|
+
private fun toLogLevel(s: String?): LogLevel =
|
|
610
|
+
LogLevel.fromWire(s ?: "") ?: LogLevel.Info
|
|
611
|
+
|
|
612
|
+
// GATED on beekon native 0.0.9 (StopReason.CloudModeUnavailable) — the new arm
|
|
613
|
+
// does not exist on the pinned 0.0.8 dep, so this `when` is non-exhaustive there.
|
|
517
614
|
private fun stopReasonToWire(r: StopReason): String = when (r) {
|
|
518
615
|
StopReason.User -> "user"
|
|
519
616
|
StopReason.PermissionDenied -> "permissionDenied"
|
|
520
617
|
StopReason.LocationServicesDisabled -> "locationServicesDisabled"
|
|
521
618
|
StopReason.LocationUnavailable -> "locationUnavailable"
|
|
619
|
+
StopReason.CloudModeUnavailable -> "cloudModeUnavailable"
|
|
522
620
|
StopReason.System -> "system"
|
|
523
621
|
}
|
|
524
622
|
|
|
@@ -580,6 +678,6 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
|
|
|
580
678
|
// Reported to the native verifier via setWrapperInfo (diagnostics only — the
|
|
581
679
|
// verifier consumes only the product). Keep in sync with package.json
|
|
582
680
|
// "version" on release.
|
|
583
|
-
private const val WRAPPER_VERSION = "0.0.
|
|
681
|
+
private const val WRAPPER_VERSION = "0.0.9"
|
|
584
682
|
}
|
|
585
683
|
}
|
package/ios/BeekonRn.mm
CHANGED
|
@@ -35,6 +35,9 @@
|
|
|
35
35
|
}
|
|
36
36
|
onLicenseStatus:^(NSDictionary *_Nonnull ls) {
|
|
37
37
|
[weakSelf emitOnLicenseStatus:ls];
|
|
38
|
+
}
|
|
39
|
+
onLog:^(NSDictionary *_Nonnull e) {
|
|
40
|
+
[weakSelf emitOnLog:e];
|
|
38
41
|
}];
|
|
39
42
|
}
|
|
40
43
|
return self;
|
|
@@ -147,6 +150,38 @@
|
|
|
147
150
|
[_impl licenseStatusWithResolver:resolve rejecter:reject];
|
|
148
151
|
}
|
|
149
152
|
|
|
153
|
+
// MARK: - Diagnostic logs
|
|
154
|
+
|
|
155
|
+
- (void)getLog:(double)fromMs
|
|
156
|
+
toMs:(double)toMs
|
|
157
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
158
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
159
|
+
[_impl getLogFromMs:fromMs toMs:toMs resolver:resolve rejecter:reject];
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
- (void)exportLog:(RCTPromiseResolveBlock)resolve
|
|
163
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
164
|
+
[_impl exportLogWithResolver:resolve rejecter:reject];
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
- (void)clearLog:(RCTPromiseResolveBlock)resolve
|
|
168
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
169
|
+
[_impl clearLogWithResolver:resolve rejecter:reject];
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
- (void)setLogLevel:(NSString *)level
|
|
173
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
174
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
175
|
+
[_impl setLogLevel:level resolver:resolve rejecter:reject];
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
- (void)log:(NSString *)level
|
|
179
|
+
message:(NSString *)message
|
|
180
|
+
resolve:(RCTPromiseResolveBlock)resolve
|
|
181
|
+
reject:(RCTPromiseRejectBlock)reject {
|
|
182
|
+
[_impl logWithLevel:level message:message resolver:resolve rejecter:reject];
|
|
183
|
+
}
|
|
184
|
+
|
|
150
185
|
- (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
|
|
151
186
|
(const facebook::react::ObjCTurboModule::InitParams &)params {
|
|
152
187
|
return std::make_shared<facebook::react::NativeBeekonRnSpecJSI>(params);
|