@wayq/beekon-rn 0.0.9 → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (49) hide show
  1. package/BeekonRn.podspec +2 -2
  2. package/CHANGELOG.md +29 -7
  3. package/LICENSE.txt +3 -3
  4. package/README.md +84 -325
  5. package/android/build.gradle +2 -2
  6. package/android/src/main/java/in/wayq/beekonrn/BeekonRnModule.kt +28 -1
  7. package/ios/BeekonRn.mm +5 -0
  8. package/ios/BeekonRn.swift +37 -1
  9. package/ios/Frameworks/BeekonKit.xcframework/LICENSE.txt +3 -3
  10. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/BeekonKit +0 -0
  11. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Info.plist +0 -0
  12. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.abi.json +254 -233
  13. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  14. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.swiftinterface +2 -2
  15. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/BeekonKit +0 -0
  16. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Info.plist +0 -0
  17. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.abi.json +254 -233
  18. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  19. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.swiftinterface +2 -2
  20. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.abi.json +254 -233
  21. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  22. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +2 -2
  23. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/_CodeSignature/CodeResources +1 -1
  24. package/lib/module/NativeBeekonRn.js +6 -0
  25. package/lib/module/NativeBeekonRn.js.map +1 -1
  26. package/lib/module/beekon.js +13 -1
  27. package/lib/module/beekon.js.map +1 -1
  28. package/lib/module/index.js.map +1 -1
  29. package/lib/module/internal/mappers.js +12 -0
  30. package/lib/module/internal/mappers.js.map +1 -1
  31. package/lib/module/types/permission.js +2 -0
  32. package/lib/module/types/permission.js.map +1 -0
  33. package/lib/typescript/src/NativeBeekonRn.d.ts +19 -0
  34. package/lib/typescript/src/NativeBeekonRn.d.ts.map +1 -1
  35. package/lib/typescript/src/beekon.d.ts +10 -0
  36. package/lib/typescript/src/beekon.d.ts.map +1 -1
  37. package/lib/typescript/src/index.d.ts +1 -0
  38. package/lib/typescript/src/index.d.ts.map +1 -1
  39. package/lib/typescript/src/internal/mappers.d.ts +3 -1
  40. package/lib/typescript/src/internal/mappers.d.ts.map +1 -1
  41. package/lib/typescript/src/types/permission.d.ts +42 -0
  42. package/lib/typescript/src/types/permission.d.ts.map +1 -0
  43. package/package.json +5 -5
  44. package/scripts/fetch-beekonkit.sh +4 -4
  45. package/src/NativeBeekonRn.ts +21 -0
  46. package/src/beekon.ts +14 -0
  47. package/src/index.tsx +5 -0
  48. package/src/internal/mappers.ts +26 -0
  49. package/src/types/permission.ts +48 -0
package/BeekonRn.podspec CHANGED
@@ -15,7 +15,7 @@ Pod::Spec.new do |s|
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" }
18
- s.source = { :git => "https://github.com/wayqteam/beekon-rn.git", :tag => "v#{s.version}" }
18
+ s.source = { :git => "https://github.com/beekonlabs/beekon-rn.git", :tag => "v#{s.version}" }
19
19
 
20
20
  s.source_files = "ios/**/*.{h,m,mm,swift,cpp}"
21
21
  # Headers are only for the auto-generated `BeekonRn-Swift.h` interop — keep
@@ -23,7 +23,7 @@ Pod::Spec.new do |s|
23
23
  s.private_header_files = "ios/**/*.h"
24
24
 
25
25
  # Native Beekon SDK as a vendored xcframework. The zip is fetched from
26
- # `wayqteam/beekon-ios-binary`'s GitHub Release at this version into
26
+ # `beekonlabs/beekon-ios-binary`'s GitHub Release at this version into
27
27
  # `ios/Frameworks/` by `scripts/fetch-beekonkit.sh`, run via `yarn prepare`,
28
28
  # and bundled in the npm tarball at publish time. SHA256 verified before
29
29
  # extraction.
package/CHANGELOG.md CHANGED
@@ -6,6 +6,28 @@ 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.1.0] - 2026-06-15
10
+
11
+ ### Changed
12
+
13
+ - **Moved to the `beekonlabs` GitHub org.** The Android native dependency
14
+ coordinate is now `io.github.beekonlabs:beekon` (was `io.github.wayqteam:beekon`),
15
+ and the iOS xcframework is fetched from `github.com/beekonlabs/beekon-ios-binary`.
16
+ This is internal to the module — the npm package name (`@wayq/beekon-rn`) is
17
+ unchanged and no consumer code changes are required.
18
+
19
+ ### Added
20
+
21
+ - **`getPermissionStatus()` — read-only permission query.** Resolves the current
22
+ location grant as a `PermissionStatus` (`level`: `notDetermined` / `denied` /
23
+ `restricted` / `foreground` / `background`; nullable `accuracy`: `full` /
24
+ `reduced`) for pre-start checks, without ever prompting. Adds the
25
+ `PermissionLevel` / `PermissionAccuracy` types and `isAuthorized` /
26
+ `canTrackInBackground`. Beekon still never *requests* permission — the app owns
27
+ that; during tracking, loss surfaces on `onState`. On Android, "not yet asked"
28
+ and "denied" both report `notDetermined`; `restricted` is iOS-only. Requires
29
+ the native SDKs ≥ the release that adds the API.
30
+
9
31
  ## [0.0.9] - 2026-06-14
10
32
 
11
33
  ### Added
@@ -34,7 +56,7 @@ Beekon is pre-1.0 — releases may contain breaking changes.
34
56
  discriminator (`'cloud'` | `'selfManaged'`) is now required. Tracking params,
35
57
  `sync`, and `licenseKey` live only on the `selfManaged` arm.
36
58
 
37
- [beekon#20]: https://github.com/wayqteam/beekon/issues/20
59
+ [beekon#20]: https://github.com/beekonlabs/beekon/issues/20
38
60
 
39
61
  ## [0.0.8]
40
62
 
@@ -43,7 +65,7 @@ No binding API changes.
43
65
 
44
66
  ### Changed
45
67
 
46
- - Native pins bumped to `0.0.8` (Maven `io.github.wayqteam:beekon`, `BeekonKit`
68
+ - Native pins bumped to `0.0.8` (Maven `io.github.beekonlabs:beekon`, `BeekonKit`
47
69
  xcframework). 0.0.8 embeds the production ES256 license verification keyset,
48
70
  so genuine `license-format-v1` tokens resolve to `licensed` / `evaluation`
49
71
  on-device, and hardens wire/license conformance. The license surface remains a
@@ -70,7 +92,7 @@ Built against the native **0.0.7** API; requires native ≥ 0.0.7 at runtime.
70
92
  degrades, or delays the SDK; Android and iOS may legally diverge for the
71
93
  same app.
72
94
  - The binding identifies itself to the verifier as the `rn` product.
73
- - Native pins bumped to `0.0.7` (Maven `io.github.wayqteam:beekon`, `BeekonKit`
95
+ - Native pins bumped to `0.0.7` (Maven `io.github.beekonlabs:beekon`, `BeekonKit`
74
96
  xcframework).
75
97
 
76
98
  ## [0.0.6]
@@ -110,7 +132,7 @@ Built against the native **0.0.6** API; requires native ≥ 0.0.6 at runtime.
110
132
  - `resumeIfNeeded()` now calls the guarded native `Beekon.resumeIfNeeded()` on
111
133
  Android (previously `Beekon.start()`): it re-adopts a previously-active,
112
134
  non-user-stopped session only, mirroring iOS.
113
- - Native pins bumped to `0.0.6` (Maven `io.github.wayqteam:beekon`, iOS
135
+ - Native pins bumped to `0.0.6` (Maven `io.github.beekonlabs:beekon`, iOS
114
136
  `BeekonKit.xcframework`).
115
137
 
116
138
  ## [0.0.5]
@@ -140,7 +162,7 @@ release. The TypeScript surface is a faithful 1:1 mirror of the native `Beekon`
140
162
  `minDistanceBetweenLocationsMeters`.
141
163
  - `getLocations(from: Date, to: Date)` replaces the prior history call.
142
164
  - Notification config is now `androidNotification` (Android-only; iOS ignores it).
143
- - Native pins bumped to `0.0.5` (Maven `io.github.wayqteam:beekon`, SwiftPM
165
+ - Native pins bumped to `0.0.5` (Maven `io.github.beekonlabs:beekon`, SwiftPM
144
166
  `beekon-ios-binary`).
145
167
 
146
168
  ### Removed
@@ -151,7 +173,7 @@ release. The TypeScript surface is a faithful 1:1 mirror of the native `Beekon`
151
173
  ## [0.0.3]
152
174
 
153
175
  First synchronized release across all four registries (Maven Central,
154
- `wayqteam/beekon-ios-binary` xcframework, pub.dev, npm). `Location`
176
+ `beekonlabs/beekon-ios-binary` xcframework, pub.dev, npm). `Location`
155
177
  accuracy/speed/bearing/altitude are nullable to faithfully represent providers
156
178
  that don't deliver them.
157
179
 
@@ -162,7 +184,7 @@ Initial release.
162
184
  ### Added
163
185
 
164
186
  - React Native (New Architecture / TurboModule) binding for the native Beekon
165
- location SDKs (Android `io.github.wayqteam:beekon`, iOS `BeekonKit`
187
+ location SDKs (Android `io.github.beekonlabs:beekon`, iOS `BeekonKit`
166
188
  xcframework).
167
189
  - Public API mirroring the native surface: `Beekon.configure / start / stop /
168
190
  getLocations`, plus `onState` / `onLocation` subscriptions.
package/LICENSE.txt CHANGED
@@ -1,9 +1,9 @@
1
1
  Beekon SDK
2
- Copyright (c) 2026 wayqteam. All rights reserved.
2
+ Copyright (c) 2026 beekonlabs. All rights reserved.
3
3
 
4
4
  This software is licensed for evaluation use only. No production deployment,
5
5
  redistribution, sublicensing, or commercial use is permitted without a separate
6
- written agreement with wayqteam.
6
+ written agreement with beekonlabs.
7
7
 
8
8
  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
9
9
  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
@@ -11,4 +11,4 @@ FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
11
11
  COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY ARISING
12
12
  FROM USE OF THE SOFTWARE.
13
13
 
14
- For licensing inquiries: contact wayqteam.
14
+ For licensing inquiries: contact beekonlabs.
package/README.md CHANGED
@@ -6,7 +6,7 @@
6
6
 
7
7
  <p align="center">
8
8
  Background location tracking for React Native.<br/>
9
- Native location stack on each platform — tracking survives backgrounding and termination.
9
+ A native location stack on each platform — tracking survives backgrounding and termination.
10
10
  </p>
11
11
 
12
12
  <p align="center">
@@ -17,24 +17,22 @@
17
17
 
18
18
  <p align="center">
19
19
  <a href="https://docs.getbeekon.com"><strong>Docs</strong></a> ·
20
- <a href="https://console.getbeekon.com"><strong>Console</strong></a> ·
21
20
  <a href="https://getbeekon.com"><strong>getbeekon.com</strong></a> ·
22
- <a href="https://github.com/wayqteam/beekon"><strong>Umbrella</strong></a>
21
+ <a href="https://github.com/beekonlabs/beekon"><strong>GitHub</strong></a>
23
22
  </p>
24
23
 
25
24
  ---
26
25
 
27
- Capture GPS in the foreground and background, keep a queryable history on the device, define geofences, and optionally sync to your own server. The JavaScript API is fully typed.
26
+ Capture location in the foreground and background, keep a queryable history on the device, define geofences, and optionally upload to a backend **you** control. Nothing leaves the device unless you set a `sync` endpoint. The JavaScript API is fully typed.
28
27
 
29
28
  ## Features
30
29
 
31
30
  - Foreground and background tracking that survives app termination
32
- - Battery-aware capture: time and distance filtering, accuracy presets, and automatic pausing while the device is stationary
31
+ - Battery-aware capture: time/distance filtering, accuracy presets, auto-pause while stationary
33
32
  - On-device history you can query at any time
34
33
  - Geofencing with enter and exit events
35
34
  - 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
35
+ - Diagnostic logging: query/export an on-device buffer, stream live entries
38
36
  - Activity detection (walking, running, cycling, automotive)
39
37
  - Built for the React Native New Architecture
40
38
 
@@ -46,19 +44,81 @@ Capture GPS in the foreground and background, keep a queryable history on the de
46
44
  | iOS | 17.0 |
47
45
  | Android | 8.0 (API level 26) |
48
46
 
49
- ## Installation
47
+ ## Install
50
48
 
51
49
  ```sh
52
50
  npm install @wayq/beekon-rn
53
51
  ```
54
52
 
55
- **iOS** — install pods:
53
+ **iOS** — `cd ios && pod install`. **Android** — no extra steps; the module links automatically. See [Setup](#permissions-and-setup) for the OS config.
56
54
 
57
- ```sh
58
- cd ios && pod install
55
+ ## Quick start
56
+
57
+ ```ts
58
+ import { Beekon } from '@wayq/beekon-rn';
59
+
60
+ const offState = Beekon.onState((state) => console.log('state:', state.kind));
61
+ const offLocation = Beekon.onLocation((loc) =>
62
+ console.log(loc.latitude, loc.longitude, loc.timestamp),
63
+ );
64
+
65
+ // Configure is optional. Request OS permissions before starting (see Setup).
66
+ await Beekon.configure({
67
+ mode: 'selfManaged',
68
+ minTimeBetweenLocationsSeconds: 30,
69
+ minDistanceBetweenLocationsMeters: 100,
70
+ });
71
+
72
+ await Beekon.start();
73
+ ```
74
+
75
+ `start()` and `stop()` never throw. Observe `onState` to learn whether tracking began and why it stopped (`'user' | 'permissionDenied' | 'locationServicesDisabled' | 'locationUnavailable' | 'system'`).
76
+
77
+ ## Send to your backend
78
+
79
+ Add a `sync` config and Beekon uploads fixes and geofence events to your backend — batched, retried, and removed from the device once your server accepts them. Without a `sync` config, all data stays on the device.
80
+
81
+ ```ts
82
+ await Beekon.configure({
83
+ mode: 'selfManaged',
84
+ sync: {
85
+ url: 'https://api.example.com/locations',
86
+ headers: { Authorization: 'Bearer <token>' },
87
+ // intervalSeconds defaults to 300, batchSize to 100
88
+ },
89
+ });
90
+
91
+ Beekon.setExtras({ userId: 'abc123' }); // attached to every upload
92
+ Beekon.onSyncStatus((status) => console.log('sync:', status.kind));
93
+ ```
94
+
95
+ Your server receives a small JSON envelope and acknowledges it with a status code. **[Build your ingest endpoint](https://docs.getbeekon.com/backend/ingest/)** is a complete, working example. For rotating bearer tokens, set `sync.auth` and the SDK attaches and **natively refreshes** the token — proactively before expiry, reactively on a `401`/`403` — even in the background. See [Auth & token refresh](https://docs.getbeekon.com/backend/auth/).
96
+
97
+ ## More
98
+
99
+ ```ts
100
+ // History (stored on the device, survives restarts)
101
+ const since = new Date(Date.now() - 24 * 60 * 60 * 1000);
102
+ const fixes = await Beekon.getLocations(since, new Date());
103
+
104
+ // Geofences — enter/exit events that keep firing across launches
105
+ await Beekon.addGeofences([
106
+ { id: 'office', latitude: 37.331, longitude: -122.031, radiusMeters: 150 },
107
+ ]);
108
+ const offGeofence = Beekon.onGeofenceEvent((e) => console.log(e.geofenceId, e.type));
109
+
110
+ // One-shot fix, independent of tracking (null on timeout)
111
+ const fix = await Beekon.getCurrentLocation();
112
+
113
+ // Pre-start permission check (the app still owns the request)
114
+ const status = await Beekon.getPermissionStatus();
115
+
116
+ // Diagnostics — runtime level, live tail, NDJSON export for bug reports
117
+ await Beekon.setLogLevel('debug');
118
+ const logPath = await Beekon.exportLog();
59
119
  ```
60
120
 
61
- **Android** — no additional steps; the module links automatically.
121
+ A **license key** is optional and purely observational `configure({ mode: 'selfManaged', licenseKey: '<JWS>' })`, then read `licenseStatus()`; without one, Beekon runs in evaluation mode. The package ships full TypeScript types, so methods, config, and events are typed in your editor. Complete API and guides: **[docs.getbeekon.com](https://docs.getbeekon.com)**.
62
122
 
63
123
  ## Permissions and setup
64
124
 
@@ -78,7 +138,7 @@ In `android/app/src/main/AndroidManifest.xml`:
78
138
  <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION" />
79
139
  ```
80
140
 
81
- While tracking, Android shows a persistent notification (required by the system). Set its title and text with the `notification` option.
141
+ While tracking, Android shows a persistent notification (required by the system). Set its title and text with the `notification` config option.
82
142
 
83
143
  ### iOS
84
144
 
@@ -103,7 +163,7 @@ In `Info.plist`:
103
163
  <string>Explain why your app detects activity.</string>
104
164
  ```
105
165
 
106
- Register Beekon's background task once during launch (required for background sync and to resume tracking after the app is terminated). In `AppDelegate.swift`:
166
+ Register Beekon's background task once during launch (required for background sync and to resume tracking after termination). In `AppDelegate.swift`:
107
167
 
108
168
  ```swift
109
169
  import BeekonRn
@@ -118,325 +178,24 @@ func application(
118
178
  }
119
179
  ```
120
180
 
121
- ## Usage
122
-
123
- ### Start tracking
124
-
125
- ```ts
126
- import { Beekon } from '@wayq/beekon-rn';
127
-
128
- const offState = Beekon.onState((state) => {
129
- console.log('state:', state.kind); // 'idle' | 'tracking' | 'stopped'
130
- });
131
-
132
- const offLocation = Beekon.onLocation((location) => {
133
- console.log(location.latitude, location.longitude, location.timestamp);
134
- });
135
-
136
- // Configure is optional. Request OS permissions before starting.
137
- await Beekon.configure({
138
- mode: 'selfManaged',
139
- minTimeBetweenLocationsSeconds: 30,
140
- minDistanceBetweenLocationsMeters: 100,
141
- });
142
-
143
- await Beekon.start();
144
-
145
- // Later:
146
- await Beekon.stop();
147
- offState();
148
- offLocation();
149
- ```
150
-
151
- `start()` and `stop()` never throw. Observe `onState` to learn whether tracking began and why it stopped:
152
-
153
- ```ts
154
- Beekon.onState((state) => {
155
- if (state.kind === 'stopped') {
156
- // 'user' | 'permissionDenied' | 'locationServicesDisabled'
157
- // | 'locationUnavailable' | 'cloudModeUnavailable' | 'system'
158
- console.log('stopped:', state.reason);
159
- }
160
- });
161
- ```
162
-
163
- ### Read history
164
-
165
- Recorded fixes are stored on the device and remain available even after the app is closed.
166
-
167
- ```ts
168
- const since = new Date(Date.now() - 24 * 60 * 60 * 1000);
169
- const fixes = await Beekon.getLocations(since, new Date());
170
-
171
- await Beekon.deleteLocations(); // delete everything
172
- await Beekon.deleteLocations(since); // delete up to a cutoff
173
- ```
174
-
175
- ### Geofences
176
-
177
- ```ts
178
- await Beekon.addGeofences([
179
- { id: 'office', latitude: 37.331, longitude: -122.031, radiusMeters: 150 },
180
- ]);
181
-
182
- const offGeofence = Beekon.onGeofenceEvent((event) => {
183
- console.log(event.geofenceId, event.type); // 'enter' | 'exit'
184
- });
185
-
186
- await Beekon.listGeofences();
187
- await Beekon.removeGeofences(['office']);
188
- ```
189
-
190
- ### Server sync
191
-
192
- Add a `sync` config to upload recorded fixes and geofence events to your backend. Uploads are batched, retried automatically, and removed from the device once your server accepts them. Without a `sync` config, all data stays on the device.
193
-
194
- ```ts
195
- await Beekon.configure({
196
- mode: 'selfManaged',
197
- sync: {
198
- url: 'https://api.example.com/locations',
199
- headers: { Authorization: 'Bearer <token>' },
200
- // intervalSeconds defaults to 300, batchSize to 100
201
- },
202
- });
203
-
204
- Beekon.setExtras({ userId: 'abc123' }); // attached to every upload
205
-
206
- Beekon.onSyncStatus((status) => {
207
- console.log('sync:', status.kind); // 'idle' | 'pending' | 'failed'
208
- });
209
- ```
210
-
211
- #### Token refresh
212
-
213
- Set `sync.auth` (an `AuthConfig`) to let the SDK attach and **natively** refresh the upload access token — proactively before it expires and reactively on a `401`/`403`, then retry the upload. This runs in the background and survives a cold launch with no host involvement. Without `auth`, a `401`/`403` pauses sync and surfaces `SyncFailure 'auth'`; re-seed by calling `configure()` again to resume.
214
-
215
- The supplied tokens are a **seed**: the SDK owns and rotates the live token set in secure storage (Keychain / encrypted prefs) after first persist. Subscribe with `onAuthTokens` to mirror rotations into your own session store.
216
-
217
- ```ts
218
- await Beekon.configure({
219
- mode: 'selfManaged',
220
- sync: {
221
- url: 'https://api.example.com/locations',
222
- auth: {
223
- accessToken: '<initial access token>',
224
- refreshToken: '<initial refresh token>',
225
- expiresAt: new Date(Date.now() + 3600_000),
226
- refreshUrl: 'https://auth.example.com/oauth/token',
227
- refreshPayload: {
228
- grant_type: 'refresh_token',
229
- refresh_token: '{refreshToken}', // substituted with the current token
230
- },
231
- // strategy defaults to 'bearer', refreshBodyFormat to 'form',
232
- // skewMarginSeconds to 60. responseMapping defaults to common-name detection.
233
- },
234
- },
235
- });
236
-
237
- const offAuth = Beekon.onAuthTokens((tokens) => {
238
- // Persist the rotated set into your own session store.
239
- console.log('rotated:', tokens.accessToken, tokens.expiresAt, tokens.epoch);
240
- });
241
- ```
242
-
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.
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
-
269
- ## Configuration
270
-
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):
272
-
273
- | Option | Default | Description |
274
- |---|---|---|
275
- | `minTimeBetweenLocationsSeconds` | `30` | Minimum seconds between recorded fixes. `0` disables the time filter. |
276
- | `minDistanceBetweenLocationsMeters` | `100` | Minimum metres between recorded fixes. `0` disables the distance filter. |
277
- | `accuracyMode` | `'balanced'` | `'high'` \| `'balanced'` \| `'low'`. Trades accuracy against battery. |
278
- | `whenStationary` | `'pause'` | `'keepTracking'` \| `'pause'` \| `'pauseWithCheckIns'`. |
279
- | `stationaryRadiusMeters` | `5` | Distance the device must move to count as moving again. |
280
- | `detectActivity` | `false` | Detect physical activity. Requires the motion permission. |
281
- | `sync` | – | Server upload settings: `{ url, headers?, intervalSeconds?, batchSize?, syncThreshold?, auth? }`. See [Token refresh](#token-refresh). |
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). |
284
-
285
- A fix is recorded only when **both** the time and distance filters are satisfied.
181
+ ## API at a glance
286
182
 
287
- ## API
183
+ Methods: `configure` · `start` · `stop` · `resumeIfNeeded` · `getCurrentLocation` · `getLocations` · `deleteLocations` · `pendingUploadCount` · `sync` · `setExtras` · `addGeofences` · `removeGeofences` · `listGeofences` · `getPermissionStatus` · `licenseStatus` · `getLog` · `exportLog` · `clearLog` · `setLogLevel` · `log`.
288
184
 
289
- | Method | Description |
290
- |---|---|
291
- | `configure(config)` | Apply settings. Optional; may be called while tracking. |
292
- | `start()` | Begin tracking. |
293
- | `stop()` | Stop tracking. |
294
- | `resumeIfNeeded()` | Resume a session that was active before the app closed. |
295
- | `getCurrentLocation(options?)` | One-shot current fix, independent of tracking. Resolves `null` on timeout. `options`: `{ timeoutMs?, accuracy? }`. |
296
- | `getLocations(from, to)` | Recorded fixes within a date range. |
297
- | `deleteLocations(before?)` | Delete fixes (all if `before` is omitted); returns the count removed. |
298
- | `pendingUploadCount()` | Number of fixes not yet uploaded. |
299
- | `sync()` | Request an immediate upload. |
300
- | `setExtras(extras)` | Custom fields included with every upload. |
301
- | `addGeofences(geofences)` | Register circular regions. |
302
- | `removeGeofences(ids)` | Unregister geofences by id. |
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`). |
310
-
311
- Subscriptions — each returns an unsubscribe function:
312
-
313
- | Subscription | Delivers |
314
- |---|---|
315
- | `onState(cb)` | Tracking state changes. The current state is delivered immediately. |
316
- | `onLocation(cb)` | Each newly recorded fix. |
317
- | `onGeofenceEvent(cb)` | Geofence enter and exit events. |
318
- | `onSyncStatus(cb)` | Upload status. The current status is delivered immediately. |
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). |
322
-
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.
185
+ Subscriptions (each returns an unsubscribe function): `onState` · `onLocation` · `onGeofenceEvent` · `onSyncStatus` · `onAuthTokens` · `onLicenseStatus` · `onLog`.
324
186
 
325
- ## Types
326
-
327
- ```ts
328
- type Location = {
329
- id: string;
330
- latitude: number;
331
- longitude: number;
332
- timestamp: Date;
333
- accuracy: number | null; // metres
334
- speed: number | null; // m/s
335
- bearing: number | null; // degrees from true north
336
- altitude: number | null; // metres
337
- quality: 'ok' | 'lowAccuracy' | 'implausibleSpeed';
338
- trigger: 'interval' | 'motion' | 'checkIn' | 'geofence' | 'manual';
339
- motion: 'moving' | 'stationary' | 'unknown';
340
- activity:
341
- | 'stationary' | 'walking' | 'running'
342
- | 'cycling' | 'automotive' | 'unknown' | null;
343
- isMock: boolean;
344
- };
345
-
346
- type BeekonState =
347
- | { kind: 'idle' }
348
- | { kind: 'tracking' }
349
- | {
350
- kind: 'stopped';
351
- reason:
352
- | 'user' | 'permissionDenied' | 'locationServicesDisabled'
353
- | 'locationUnavailable' | 'cloudModeUnavailable' | 'system';
354
- };
355
-
356
- type SyncStatus =
357
- | { kind: 'idle' }
358
- | { kind: 'pending' }
359
- | { kind: 'failed'; reason: 'auth' | 'rejected' };
360
-
361
- type BeekonGeofence = {
362
- id: string;
363
- latitude: number;
364
- longitude: number;
365
- radiusMeters: number;
366
- notifyOnEntry?: boolean; // default true
367
- notifyOnExit?: boolean; // default true
368
- };
369
-
370
- type GeofenceEvent = {
371
- id: string;
372
- geofenceId: string;
373
- type: 'enter' | 'exit';
374
- timestamp: Date;
375
- };
376
-
377
- // Set on `SyncConfig.auth` to enable native token refresh. The token fields are
378
- // a seed — the SDK rotates them after first persist.
379
- type AuthConfig = {
380
- accessToken?: string;
381
- refreshToken?: string;
382
- expiresAt?: Date;
383
- strategy?: 'bearer' | 'raw'; // default 'bearer'
384
- refreshUrl?: string; // omit to disable refresh
385
- refreshPayload?: Record<string, string>; // '{refreshToken}' substituted
386
- refreshHeaders?: Record<string, string>; // '{accessToken}' substituted
387
- refreshBodyFormat?: 'form' | 'json'; // default 'form'
388
- responseMapping?: {
389
- accessToken?: string;
390
- refreshToken?: string;
391
- expiresIn?: string;
392
- expiresAt?: string;
393
- };
394
- skewMarginSeconds?: number; // default 60
395
- seedEpoch?: number;
396
- };
397
-
398
- // Delivered by `onAuthTokens` after each native rotation. Sensitive — in-process
399
- // only, never logged.
400
- type AuthTokens = {
401
- accessToken: string;
402
- refreshToken: string | null;
403
- expiresAt: Date | null;
404
- epoch: number; // monotonic generation, bumped on each refresh
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
- };
430
- ```
431
-
432
- Optional numeric fields on `Location` are `null` when the device did not report them — never `0`.
187
+ Every method, type, and event is documented at **[docs.getbeekon.com](https://docs.getbeekon.com)** and typed in the package.
433
188
 
434
189
  ## Notes
435
190
 
436
- - **Retention.** Fixes are kept on the device for up to 7 days, or the most recent 100,000 fixes, whichever comes first.
437
- - **Background relaunch.** Call `resumeIfNeeded()` early in your app to restore tracking after the system terminates it. On Android, also resume from your `Application.onCreate` (see the example app).
191
+ - **Retention.** Fixes are kept for up to 7 days, or the most recent 100,000 fixes, whichever comes first.
192
+ - **Background relaunch.** Call `resumeIfNeeded()` early in startup to restore tracking after the system terminates the app. On Android, also resume from `Application.onCreate` (see the example app).
438
193
  - **Android background limits.** Some manufacturers aggressively stop background services; if tracking halts unexpectedly, see [dontkillmyapp.com](https://dontkillmyapp.com).
439
194
 
195
+ ## Beekon Cloud
196
+
197
+ Prefer managed ingest, a console, and server-owned config instead of running your own backend? **Beekon Cloud** is in private beta — see the [docs](https://docs.getbeekon.com/cloud/).
198
+
440
199
  ## Example
441
200
 
442
201
  A complete, runnable example is in the [`example/`](./example) directory.
@@ -1,7 +1,7 @@
1
1
  buildscript {
2
2
  ext.BeekonRn = [
3
3
  kotlinVersion: "2.1.20",
4
- // minSdk 26 is required by the native Beekon AAR (io.github.wayqteam:beekon).
4
+ // minSdk 26 is required by the native Beekon AAR (io.github.beekonlabs:beekon).
5
5
  minSdkVersion: 26,
6
6
  compileSdkVersion: 36,
7
7
  targetSdkVersion: 36
@@ -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.9"
82
+ implementation "io.github.beekonlabs:beekon:0.1.0"
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.