@wayq/beekon-rn 0.0.1
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 +37 -0
- package/LICENSE.txt +14 -0
- package/README.md +122 -0
- package/android/build.gradle +81 -0
- package/android/src/main/AndroidManifest.xml +2 -0
- package/android/src/main/java/com/wayq/beekonrn/BeekonRnModule.kt +233 -0
- package/android/src/main/java/com/wayq/beekonrn/BeekonRnPackage.kt +31 -0
- package/ios/BeekonRn.h +5 -0
- package/ios/BeekonRn.mm +80 -0
- package/ios/BeekonRn.swift +211 -0
- package/ios/Frameworks/BeekonKit.xcframework/Info.plist +44 -0
- package/ios/Frameworks/BeekonKit.xcframework/LICENSE.txt +14 -0
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeDirectory +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeRequirements +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeRequirements-1 +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeResources +233 -0
- package/ios/Frameworks/BeekonKit.xcframework/_CodeSignature/CodeSignature +0 -0
- 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/PrivacyInfo.xcprivacy +77 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/_CodeSignature/CodeResources +113 -0
- 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/PrivacyInfo.xcprivacy +77 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/_CodeSignature/CodeResources +113 -0
- package/lib/module/NativeBeekonRn.js +16 -0
- package/lib/module/NativeBeekonRn.js.map +1 -0
- package/lib/module/beekon.js +107 -0
- package/lib/module/beekon.js.map +1 -0
- package/lib/module/index.js +4 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/internal/mappers.js +58 -0
- package/lib/module/internal/mappers.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/types/config.js +4 -0
- package/lib/module/types/config.js.map +1 -0
- package/lib/module/types/position.js +2 -0
- package/lib/module/types/position.js.map +1 -0
- package/lib/module/types/preset.js +2 -0
- package/lib/module/types/preset.js.map +1 -0
- package/lib/module/types/state.js +2 -0
- package/lib/module/types/state.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/NativeBeekonRn.d.ts +58 -0
- package/lib/typescript/src/NativeBeekonRn.d.ts.map +1 -0
- package/lib/typescript/src/beekon.d.ts +80 -0
- package/lib/typescript/src/beekon.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +6 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/internal/mappers.d.ts +8 -0
- package/lib/typescript/src/internal/mappers.d.ts.map +1 -0
- package/lib/typescript/src/types/config.d.ts +41 -0
- package/lib/typescript/src/types/config.d.ts.map +1 -0
- package/lib/typescript/src/types/position.d.ts +24 -0
- package/lib/typescript/src/types/position.d.ts.map +1 -0
- package/lib/typescript/src/types/preset.d.ts +12 -0
- package/lib/typescript/src/types/preset.d.ts.map +1 -0
- package/lib/typescript/src/types/state.d.ts +22 -0
- package/lib/typescript/src/types/state.d.ts.map +1 -0
- package/package.json +137 -0
- package/scripts/fetch-beekonkit.sh +58 -0
- package/src/NativeBeekonRn.ts +64 -0
- package/src/beekon.ts +110 -0
- package/src/index.tsx +5 -0
- package/src/internal/mappers.ts +50 -0
- package/src/types/config.ts +42 -0
- package/src/types/position.ts +23 -0
- package/src/types/preset.ts +11 -0
- package/src/types/state.ts +16 -0
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import type { BeekonConfig } from './types/config';
|
|
2
|
+
import type { BeekonState } from './types/state';
|
|
3
|
+
import type { Position } from './types/position';
|
|
4
|
+
/**
|
|
5
|
+
* Public facade for the Beekon SDK. Mirrors the native APIs:
|
|
6
|
+
*
|
|
7
|
+
* - Android: `com.wayq.beekon.Beekon` (object)
|
|
8
|
+
* - iOS: `Beekon.shared` (actor)
|
|
9
|
+
*
|
|
10
|
+
* Lifecycle: `init()` once → `configure(config)` → `start()` → ... →
|
|
11
|
+
* `stop()` (idempotent) or `shutdown()` (final teardown). Subscribe to
|
|
12
|
+
* `onState` / `onPosition` for live updates; query `history(from, to)` for
|
|
13
|
+
* persisted points.
|
|
14
|
+
*
|
|
15
|
+
* **Threading:** Methods are safe to call from any JS context. Subscribers'
|
|
16
|
+
* callbacks fire on the JS thread.
|
|
17
|
+
*
|
|
18
|
+
* **Persistence invariant:** the SDK persists every gated position natively;
|
|
19
|
+
* JS is a passive observer. In background, the JS engine is not guaranteed to
|
|
20
|
+
* be alive — for past points, use `history()`.
|
|
21
|
+
*/
|
|
22
|
+
declare class BeekonImpl {
|
|
23
|
+
/**
|
|
24
|
+
* Initialize the SDK. Idempotent; safe to call more than once. Must be
|
|
25
|
+
* called once before `configure()`.
|
|
26
|
+
*
|
|
27
|
+
* Errors:
|
|
28
|
+
* - `NO_GMS_AVAILABLE` (Android) — Google Play Services missing.
|
|
29
|
+
*/
|
|
30
|
+
init(): Promise<void>;
|
|
31
|
+
/**
|
|
32
|
+
* Set sampling and platform-specific config. Replaces any previous config.
|
|
33
|
+
* Must be called before `start()`.
|
|
34
|
+
*
|
|
35
|
+
* Errors:
|
|
36
|
+
* - `NOT_INITIALISED` — `init()` was not called first.
|
|
37
|
+
* - `NOT_CONFIGURED` — Android only, `androidNotification` was missing.
|
|
38
|
+
*/
|
|
39
|
+
configure(config: BeekonConfig): Promise<void>;
|
|
40
|
+
/**
|
|
41
|
+
* Begin tracking. Transitions state from `idle` → `starting` → `tracking`.
|
|
42
|
+
*
|
|
43
|
+
* Errors:
|
|
44
|
+
* - `PERMISSION_DENIED` — location permission not granted.
|
|
45
|
+
* - `LOCATION_SERVICES_DISABLED` (iOS) — system location services off.
|
|
46
|
+
* - `SERVICE_FAILED` — native service couldn't start.
|
|
47
|
+
*/
|
|
48
|
+
start(): Promise<void>;
|
|
49
|
+
/** Stop tracking. Idempotent. State → `stopped`. */
|
|
50
|
+
stop(): Promise<void>;
|
|
51
|
+
/**
|
|
52
|
+
* Final teardown — releases native resources. Most apps don't need this;
|
|
53
|
+
* `stop()` is sufficient between sessions.
|
|
54
|
+
*/
|
|
55
|
+
shutdown(): Promise<void>;
|
|
56
|
+
/**
|
|
57
|
+
* Read persisted positions in the time range [from, to]. Returns positions
|
|
58
|
+
* in chronological order. Reads come from the SDK's local storage (Room on
|
|
59
|
+
* Android, GRDB on iOS) — the source of truth even when JS was asleep.
|
|
60
|
+
*
|
|
61
|
+
* Retention: positions older than 7 days OR beyond the most recent 100K are
|
|
62
|
+
* pruned automatically.
|
|
63
|
+
*/
|
|
64
|
+
history(from: Date, to: Date): Promise<Position[]>;
|
|
65
|
+
/**
|
|
66
|
+
* Subscribe to state transitions. Returns an unsubscribe function. The
|
|
67
|
+
* current state is delivered to new subscribers immediately (replay-1
|
|
68
|
+
* semantics, matching the native `state` flow).
|
|
69
|
+
*/
|
|
70
|
+
onState(cb: (s: BeekonState) => void): () => void;
|
|
71
|
+
/**
|
|
72
|
+
* Subscribe to gated positions as they arrive. Returns an unsubscribe
|
|
73
|
+
* function. Broadcast (no replay) — only delivers while the JS engine is
|
|
74
|
+
* alive. For points emitted while JS was asleep, use `history()`.
|
|
75
|
+
*/
|
|
76
|
+
onPosition(cb: (p: Position) => void): () => void;
|
|
77
|
+
}
|
|
78
|
+
export declare const Beekon: BeekonImpl;
|
|
79
|
+
export {};
|
|
80
|
+
//# sourceMappingURL=beekon.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"beekon.d.ts","sourceRoot":"","sources":["../../../src/beekon.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AACjD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAGjD;;;;;;;;;;;;;;;;;GAiBG;AACH,cAAM,UAAU;IACd;;;;;;OAMG;IACG,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B;;;;;;;OAOG;IACG,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC;IAIpD;;;;;;;OAOG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAI5B,oDAAoD;IAC9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAI3B;;;OAGG;IACG,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAI/B;;;;;;;OAOG;IACG,OAAO,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,EAAE,IAAI,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC;IAKxD;;;;OAIG;IACH,OAAO,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,WAAW,KAAK,IAAI,GAAG,MAAM,IAAI;IAKjD;;;;OAIG;IACH,UAAU,CAAC,EAAE,EAAE,CAAC,CAAC,EAAE,QAAQ,KAAK,IAAI,GAAG,MAAM,IAAI;CAMlD;AAED,eAAO,MAAM,MAAM,YAAmB,CAAC"}
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export { Beekon } from './beekon';
|
|
2
|
+
export type { BeekonConfig, AndroidNotificationConfig } from './types/config';
|
|
3
|
+
export type { Preset } from './types/preset';
|
|
4
|
+
export type { BeekonState, PauseReason } from './types/state';
|
|
5
|
+
export type { Position } from './types/position';
|
|
6
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAClC,YAAY,EAAE,YAAY,EAAE,yBAAyB,EAAE,MAAM,gBAAgB,CAAC;AAC9E,YAAY,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAC7C,YAAY,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAC9D,YAAY,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { BeekonConfig } from '../types/config';
|
|
2
|
+
import type { BeekonState } from '../types/state';
|
|
3
|
+
import type { Position } from '../types/position';
|
|
4
|
+
import type { WireConfig, WirePosition, WireState } from '../NativeBeekonRn';
|
|
5
|
+
export declare function configToWire(config: BeekonConfig): WireConfig;
|
|
6
|
+
export declare function wireToPosition(w: WirePosition): Position;
|
|
7
|
+
export declare function wireToState(w: WireState): BeekonState;
|
|
8
|
+
//# sourceMappingURL=mappers.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mappers.d.ts","sourceRoot":"","sources":["../../../../src/internal/mappers.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AACpD,OAAO,KAAK,EAAE,WAAW,EAAe,MAAM,gBAAgB,CAAC;AAC/D,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAClD,OAAO,KAAK,EAAE,UAAU,EAAE,YAAY,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAE7E,wBAAgB,YAAY,CAAC,MAAM,EAAE,YAAY,GAAG,UAAU,CAQ7D;AAED,wBAAgB,cAAc,CAAC,CAAC,EAAE,YAAY,GAAG,QAAQ,CAUxD;AAOD,wBAAgB,WAAW,CAAC,CAAC,EAAE,SAAS,GAAG,WAAW,CAiBrD"}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { Preset } from './preset';
|
|
2
|
+
/**
|
|
3
|
+
* Foreground service notification config — required when running on Android
|
|
4
|
+
* because Android 8+ requires a persistent notification while a foreground
|
|
5
|
+
* service is active. Ignored on iOS.
|
|
6
|
+
*/
|
|
7
|
+
export type AndroidNotificationConfig = {
|
|
8
|
+
/** NotificationChannel id (Android 8+). */
|
|
9
|
+
channelId: string;
|
|
10
|
+
/** User-visible channel display name. */
|
|
11
|
+
channelName: string;
|
|
12
|
+
/** Foreground notification id. Must be > 0. */
|
|
13
|
+
notificationId: number;
|
|
14
|
+
/** Notification title shown in the status bar. */
|
|
15
|
+
title: string;
|
|
16
|
+
/** Notification body text. */
|
|
17
|
+
text: string;
|
|
18
|
+
/**
|
|
19
|
+
* Drawable resource name for the notification icon (e.g. `ic_notification`).
|
|
20
|
+
* Resolved at runtime via `Resources.getIdentifier()` against the host app's
|
|
21
|
+
* `res/drawable*` folders. Pass the resource name without extension or
|
|
22
|
+
* `R.drawable.` prefix.
|
|
23
|
+
*/
|
|
24
|
+
smallIconResName: string;
|
|
25
|
+
};
|
|
26
|
+
export type BeekonConfig = {
|
|
27
|
+
/** Sampling preset. Default: `'balanced'`. */
|
|
28
|
+
preset?: Preset;
|
|
29
|
+
/** Override the preset's distance gate (meters). */
|
|
30
|
+
distanceFilterMeters?: number;
|
|
31
|
+
/** Override the preset's interval (milliseconds). */
|
|
32
|
+
intervalMillis?: number;
|
|
33
|
+
/**
|
|
34
|
+
* Required when running on Android. Ignored on iOS. The plugin throws
|
|
35
|
+
* `NOT_CONFIGURED` if missing on Android.
|
|
36
|
+
*/
|
|
37
|
+
androidNotification?: AndroidNotificationConfig;
|
|
38
|
+
/** Optional license key. Reserved for future use. */
|
|
39
|
+
licenseKey?: string;
|
|
40
|
+
};
|
|
41
|
+
//# sourceMappingURL=config.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../../../../src/types/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,UAAU,CAAC;AAEvC;;;;GAIG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,yCAAyC;IACzC,WAAW,EAAE,MAAM,CAAC;IACpB,+CAA+C;IAC/C,cAAc,EAAE,MAAM,CAAC;IACvB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,8BAA8B;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb;;;;;OAKG;IACH,gBAAgB,EAAE,MAAM,CAAC;CAC1B,CAAC;AAEF,MAAM,MAAM,YAAY,GAAG;IACzB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,oDAAoD;IACpD,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,qDAAqD;IACrD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,yBAAyB,CAAC;IAChD,qDAAqD;IACrD,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* A single location fix as emitted by the native SDK after gating. Fields map
|
|
3
|
+
* 1:1 to `com.wayq.beekon.Position` on Android and `Beekon.Position` on iOS.
|
|
4
|
+
*
|
|
5
|
+
* The SDK does NOT smooth or filter positions beyond the gate — values are
|
|
6
|
+
* forwarded as the OS provider reported them (raw passthrough).
|
|
7
|
+
*/
|
|
8
|
+
export type Position = {
|
|
9
|
+
/** Latitude in degrees, WGS-84. */
|
|
10
|
+
lat: number;
|
|
11
|
+
/** Longitude in degrees, WGS-84. */
|
|
12
|
+
lng: number;
|
|
13
|
+
/** Horizontal accuracy in meters (1-sigma). */
|
|
14
|
+
accuracy: number;
|
|
15
|
+
/** Speed in m/s. May be 0 if the OS provider doesn't supply it. */
|
|
16
|
+
speed: number;
|
|
17
|
+
/** Bearing in degrees clockwise from true north. */
|
|
18
|
+
bearing: number;
|
|
19
|
+
/** Altitude in meters above the WGS-84 ellipsoid. */
|
|
20
|
+
altitude: number;
|
|
21
|
+
/** Time the OS provider reported this fix (not when JS received it). */
|
|
22
|
+
timestamp: Date;
|
|
23
|
+
};
|
|
24
|
+
//# sourceMappingURL=position.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"position.d.ts","sourceRoot":"","sources":["../../../../src/types/position.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,mCAAmC;IACnC,GAAG,EAAE,MAAM,CAAC;IACZ,oCAAoC;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,+CAA+C;IAC/C,QAAQ,EAAE,MAAM,CAAC;IACjB,mEAAmE;IACnE,KAAK,EAAE,MAAM,CAAC;IACd,oDAAoD;IACpD,OAAO,EAAE,MAAM,CAAC;IAChB,qDAAqD;IACrD,QAAQ,EAAE,MAAM,CAAC;IACjB,wEAAwE;IACxE,SAAS,EAAE,IAAI,CAAC;CACjB,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Sampling preset. Determines the gating interval and distance threshold the
|
|
3
|
+
* native SDK uses before emitting a position. Per `docs/REQUIREMENTS.md`:
|
|
4
|
+
*
|
|
5
|
+
* | Preset | Interval | Distance | Battery (typical) |
|
|
6
|
+
* |-----------|----------|----------|-------------------|
|
|
7
|
+
* | saver | 60_000ms | 150 m | 3–8% |
|
|
8
|
+
* | balanced | 30_000ms | 100 m | 5–10% |
|
|
9
|
+
* | precision | 10_000ms | 30 m | 15–25% |
|
|
10
|
+
*/
|
|
11
|
+
export type Preset = 'saver' | 'balanced' | 'precision';
|
|
12
|
+
//# sourceMappingURL=preset.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"preset.d.ts","sourceRoot":"","sources":["../../../../src/types/preset.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,MAAM,MAAM,GAAG,OAAO,GAAG,UAAU,GAAG,WAAW,CAAC"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Why tracking is paused. Names match the native `PauseReason` enum on both
|
|
3
|
+
* platforms byte-for-byte.
|
|
4
|
+
*/
|
|
5
|
+
export type PauseReason = 'permissionRevoked' | 'locationDisabled' | 'unknown';
|
|
6
|
+
/**
|
|
7
|
+
* Tracking state. Mirrors the native `BeekonState` sealed hierarchy on both
|
|
8
|
+
* platforms. Use the `kind` field as a discriminator.
|
|
9
|
+
*/
|
|
10
|
+
export type BeekonState = {
|
|
11
|
+
kind: 'idle';
|
|
12
|
+
} | {
|
|
13
|
+
kind: 'starting';
|
|
14
|
+
} | {
|
|
15
|
+
kind: 'tracking';
|
|
16
|
+
} | {
|
|
17
|
+
kind: 'paused';
|
|
18
|
+
reason: PauseReason;
|
|
19
|
+
} | {
|
|
20
|
+
kind: 'stopped';
|
|
21
|
+
};
|
|
22
|
+
//# sourceMappingURL=state.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../../../../src/types/state.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG,mBAAmB,GAAG,kBAAkB,GAAG,SAAS,CAAC;AAE/E;;;GAGG;AACH,MAAM,MAAM,WAAW,GACnB;IAAE,IAAI,EAAE,MAAM,CAAA;CAAE,GAChB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,UAAU,CAAA;CAAE,GACpB;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,MAAM,EAAE,WAAW,CAAA;CAAE,GACvC;IAAE,IAAI,EAAE,SAAS,CAAA;CAAE,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@wayq/beekon-rn",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"description": "React Native binding for the Beekon location SDK (Android + iOS).",
|
|
5
|
+
"main": "./lib/module/index.js",
|
|
6
|
+
"types": "./lib/typescript/src/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"source": "./src/index.tsx",
|
|
10
|
+
"types": "./lib/typescript/src/index.d.ts",
|
|
11
|
+
"default": "./lib/module/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"src",
|
|
17
|
+
"lib",
|
|
18
|
+
"android",
|
|
19
|
+
"ios",
|
|
20
|
+
"scripts/fetch-beekonkit.sh",
|
|
21
|
+
"*.podspec",
|
|
22
|
+
"LICENSE.txt",
|
|
23
|
+
"!ios/build",
|
|
24
|
+
"!android/build",
|
|
25
|
+
"!android/gradle",
|
|
26
|
+
"!android/gradlew",
|
|
27
|
+
"!android/gradlew.bat",
|
|
28
|
+
"!android/local.properties",
|
|
29
|
+
"!**/__tests__",
|
|
30
|
+
"!**/__fixtures__",
|
|
31
|
+
"!**/__mocks__",
|
|
32
|
+
"!**/.*"
|
|
33
|
+
],
|
|
34
|
+
"scripts": {
|
|
35
|
+
"example": "yarn workspace @wayq/beekon-rn-example",
|
|
36
|
+
"clean": "del-cli android/build example/android/build example/android/app/build example/ios/build ios/Frameworks lib",
|
|
37
|
+
"fetch-beekonkit": "bash scripts/fetch-beekonkit.sh",
|
|
38
|
+
"prepare": "yarn fetch-beekonkit && bob build",
|
|
39
|
+
"typecheck": "tsc",
|
|
40
|
+
"lint": "eslint \"**/*.{js,ts,tsx}\""
|
|
41
|
+
},
|
|
42
|
+
"keywords": [
|
|
43
|
+
"react-native",
|
|
44
|
+
"ios",
|
|
45
|
+
"android",
|
|
46
|
+
"location",
|
|
47
|
+
"tracking",
|
|
48
|
+
"gps",
|
|
49
|
+
"background-location",
|
|
50
|
+
"geolocation",
|
|
51
|
+
"beekon",
|
|
52
|
+
"turbo-module"
|
|
53
|
+
],
|
|
54
|
+
"repository": {
|
|
55
|
+
"type": "git",
|
|
56
|
+
"url": "git+https://github.com/wayqteam/beekon.git",
|
|
57
|
+
"directory": "beekon-rn"
|
|
58
|
+
},
|
|
59
|
+
"author": "wayqteam <wayqteam@users.noreply.github.com> (https://github.com/wayqteam)",
|
|
60
|
+
"license": "SEE LICENSE IN LICENSE.txt",
|
|
61
|
+
"bugs": {
|
|
62
|
+
"url": "https://github.com/wayqteam/beekon/issues"
|
|
63
|
+
},
|
|
64
|
+
"homepage": "https://github.com/wayqteam/beekon/tree/main/beekon-rn#readme",
|
|
65
|
+
"publishConfig": {
|
|
66
|
+
"registry": "https://registry.npmjs.org/",
|
|
67
|
+
"access": "public"
|
|
68
|
+
},
|
|
69
|
+
"devDependencies": {
|
|
70
|
+
"@eslint/compat": "^2.0.3",
|
|
71
|
+
"@eslint/eslintrc": "^3.3.5",
|
|
72
|
+
"@eslint/js": "^10.0.1",
|
|
73
|
+
"@react-native/babel-preset": "0.85.0",
|
|
74
|
+
"@react-native/eslint-config": "0.85.0",
|
|
75
|
+
"@types/react": "^19.2.0",
|
|
76
|
+
"del-cli": "^7.0.0",
|
|
77
|
+
"eslint": "^9.39.4",
|
|
78
|
+
"eslint-config-prettier": "^10.1.8",
|
|
79
|
+
"eslint-plugin-ft-flow": "^3.0.11",
|
|
80
|
+
"eslint-plugin-prettier": "^5.5.5",
|
|
81
|
+
"prettier": "^3.8.1",
|
|
82
|
+
"react": "19.2.3",
|
|
83
|
+
"react-native": "0.85.0",
|
|
84
|
+
"react-native-builder-bob": "^0.41.0",
|
|
85
|
+
"turbo": "^2.8.21",
|
|
86
|
+
"typescript": "^6.0.2"
|
|
87
|
+
},
|
|
88
|
+
"peerDependencies": {
|
|
89
|
+
"react": "*",
|
|
90
|
+
"react-native": "*"
|
|
91
|
+
},
|
|
92
|
+
"workspaces": [
|
|
93
|
+
"example"
|
|
94
|
+
],
|
|
95
|
+
"packageManager": "yarn@4.11.0",
|
|
96
|
+
"react-native-builder-bob": {
|
|
97
|
+
"source": "src",
|
|
98
|
+
"output": "lib",
|
|
99
|
+
"targets": [
|
|
100
|
+
[
|
|
101
|
+
"module",
|
|
102
|
+
{
|
|
103
|
+
"esm": true
|
|
104
|
+
}
|
|
105
|
+
],
|
|
106
|
+
[
|
|
107
|
+
"typescript",
|
|
108
|
+
{
|
|
109
|
+
"project": "tsconfig.build.json"
|
|
110
|
+
}
|
|
111
|
+
]
|
|
112
|
+
]
|
|
113
|
+
},
|
|
114
|
+
"codegenConfig": {
|
|
115
|
+
"name": "BeekonRnSpec",
|
|
116
|
+
"type": "modules",
|
|
117
|
+
"jsSrcsDir": "src",
|
|
118
|
+
"android": {
|
|
119
|
+
"javaPackageName": "com.wayq.beekonrn"
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
"prettier": {
|
|
123
|
+
"quoteProps": "consistent",
|
|
124
|
+
"singleQuote": true,
|
|
125
|
+
"tabWidth": 2,
|
|
126
|
+
"trailingComma": "es5",
|
|
127
|
+
"useTabs": false
|
|
128
|
+
},
|
|
129
|
+
"create-react-native-library": {
|
|
130
|
+
"type": "turbo-module",
|
|
131
|
+
"languages": "kotlin-objc",
|
|
132
|
+
"tools": [
|
|
133
|
+
"eslint"
|
|
134
|
+
],
|
|
135
|
+
"version": "0.62.0"
|
|
136
|
+
}
|
|
137
|
+
}
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# Fetches BeekonKit.xcframework from wayqteam/beekon-ios-binary's GitHub
|
|
3
|
+
# Release at the pinned version, verifies SHA256, and extracts it into
|
|
4
|
+
# ios/Frameworks/. Idempotent: skips if the framework is already present.
|
|
5
|
+
#
|
|
6
|
+
# Run via `yarn prepare` (CI: pre-publish) and once locally before iOS dev
|
|
7
|
+
# (e.g. `bash scripts/fetch-beekonkit.sh` → `cd example/ios && pod install`).
|
|
8
|
+
#
|
|
9
|
+
# The SHA256 must match the value posted in the binary repo's release notes,
|
|
10
|
+
# and the URL must match the binary repo's `Package.swift` entry. Bumping the
|
|
11
|
+
# native version means updating BOTH constants below (and in the podspec
|
|
12
|
+
# comment), then re-running.
|
|
13
|
+
|
|
14
|
+
set -euo pipefail
|
|
15
|
+
|
|
16
|
+
VERSION="0.0.1"
|
|
17
|
+
URL="https://github.com/wayqteam/beekon-ios-binary/releases/download/v${VERSION}/BeekonKit.xcframework.zip"
|
|
18
|
+
EXPECTED_SHA="f7bd79a6d61994977318daa6d722866abd0a61d7d7e5834ab5307df39b6ee60e"
|
|
19
|
+
|
|
20
|
+
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
21
|
+
DEST_DIR="${ROOT}/ios/Frameworks"
|
|
22
|
+
TARGET="${DEST_DIR}/BeekonKit.xcframework"
|
|
23
|
+
|
|
24
|
+
if [ -d "${TARGET}" ]; then
|
|
25
|
+
echo "fetch-beekonkit: ${TARGET} already present, skipping"
|
|
26
|
+
exit 0
|
|
27
|
+
fi
|
|
28
|
+
|
|
29
|
+
mkdir -p "${DEST_DIR}"
|
|
30
|
+
ZIP="${DEST_DIR}/BeekonKit.xcframework.zip"
|
|
31
|
+
|
|
32
|
+
echo "fetch-beekonkit: downloading ${URL}"
|
|
33
|
+
curl -fsSL "${URL}" -o "${ZIP}"
|
|
34
|
+
|
|
35
|
+
# `shasum` ships with macOS, `sha256sum` with most Linux distros. CI publish
|
|
36
|
+
# runs on Linux for cost reasons, so support both.
|
|
37
|
+
if command -v shasum >/dev/null 2>&1; then
|
|
38
|
+
actual=$(shasum -a 256 "${ZIP}" | awk '{print $1}')
|
|
39
|
+
elif command -v sha256sum >/dev/null 2>&1; then
|
|
40
|
+
actual=$(sha256sum "${ZIP}" | awk '{print $1}')
|
|
41
|
+
else
|
|
42
|
+
echo "fetch-beekonkit: neither shasum nor sha256sum found in PATH" >&2
|
|
43
|
+
rm -f "${ZIP}"
|
|
44
|
+
exit 1
|
|
45
|
+
fi
|
|
46
|
+
|
|
47
|
+
if [ "${actual}" != "${EXPECTED_SHA}" ]; then
|
|
48
|
+
echo "fetch-beekonkit: SHA256 mismatch" >&2
|
|
49
|
+
echo " expected: ${EXPECTED_SHA}" >&2
|
|
50
|
+
echo " actual: ${actual}" >&2
|
|
51
|
+
rm -f "${ZIP}"
|
|
52
|
+
exit 1
|
|
53
|
+
fi
|
|
54
|
+
|
|
55
|
+
echo "fetch-beekonkit: SHA256 verified, extracting"
|
|
56
|
+
unzip -q -o "${ZIP}" -d "${DEST_DIR}"
|
|
57
|
+
rm "${ZIP}"
|
|
58
|
+
echo "fetch-beekonkit: ${TARGET} ready"
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Codegen TurboModule spec — DO NOT export Wire* types from `src/index.tsx`.
|
|
3
|
+
* The public TS API in `src/beekon.ts` and `src/types/` is what consumers use;
|
|
4
|
+
* mappers in `src/internal/mappers.ts` convert between the two.
|
|
5
|
+
*
|
|
6
|
+
* Wire types are flat (primitives + nested flat objects) because Codegen's
|
|
7
|
+
* TS-to-Kotlin/ObjC type derivation has limited support for unions and
|
|
8
|
+
* recursive structures. State variants are encoded as a `type` discriminator
|
|
9
|
+
* string with sibling fields nullable per variant.
|
|
10
|
+
*/
|
|
11
|
+
import type { CodegenTypes, TurboModule } from 'react-native';
|
|
12
|
+
import { TurboModuleRegistry } from 'react-native';
|
|
13
|
+
|
|
14
|
+
export type WireAndroidNotification = {
|
|
15
|
+
channelId: string;
|
|
16
|
+
channelName: string;
|
|
17
|
+
notificationId: number;
|
|
18
|
+
title: string;
|
|
19
|
+
text: string;
|
|
20
|
+
smallIconResName: string;
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
export type WireConfig = {
|
|
24
|
+
/** One of: 'saver' | 'balanced' | 'precision'. */
|
|
25
|
+
preset: string;
|
|
26
|
+
distanceFilterMeters?: number;
|
|
27
|
+
intervalMillis?: number;
|
|
28
|
+
androidNotification?: WireAndroidNotification;
|
|
29
|
+
licenseKey?: string;
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
export type WirePosition = {
|
|
33
|
+
lat: number;
|
|
34
|
+
lng: number;
|
|
35
|
+
accuracy: number;
|
|
36
|
+
speed: number;
|
|
37
|
+
bearing: number;
|
|
38
|
+
altitude: number;
|
|
39
|
+
timestampMs: number;
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
export type WireState = {
|
|
43
|
+
/** One of: 'idle' | 'starting' | 'tracking' | 'paused' | 'stopped'. */
|
|
44
|
+
type: string;
|
|
45
|
+
/**
|
|
46
|
+
* Only populated when `type === 'paused'`. One of:
|
|
47
|
+
* 'permissionRevoked' | 'locationDisabled' | 'unknown'.
|
|
48
|
+
*/
|
|
49
|
+
pauseReason?: string;
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export interface Spec extends TurboModule {
|
|
53
|
+
initialize(): Promise<void>;
|
|
54
|
+
configure(config: WireConfig): Promise<void>;
|
|
55
|
+
start(): Promise<void>;
|
|
56
|
+
stop(): Promise<void>;
|
|
57
|
+
shutdown(): Promise<void>;
|
|
58
|
+
history(fromMs: number, toMs: number): Promise<WirePosition[]>;
|
|
59
|
+
|
|
60
|
+
readonly onState: CodegenTypes.EventEmitter<WireState>;
|
|
61
|
+
readonly onPosition: CodegenTypes.EventEmitter<WirePosition>;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export default TurboModuleRegistry.getEnforcing<Spec>('BeekonRn');
|
package/src/beekon.ts
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import NativeBeekon from './NativeBeekonRn';
|
|
2
|
+
import type { BeekonConfig } from './types/config';
|
|
3
|
+
import type { BeekonState } from './types/state';
|
|
4
|
+
import type { Position } from './types/position';
|
|
5
|
+
import { configToWire, wireToPosition, wireToState } from './internal/mappers';
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Public facade for the Beekon SDK. Mirrors the native APIs:
|
|
9
|
+
*
|
|
10
|
+
* - Android: `com.wayq.beekon.Beekon` (object)
|
|
11
|
+
* - iOS: `Beekon.shared` (actor)
|
|
12
|
+
*
|
|
13
|
+
* Lifecycle: `init()` once → `configure(config)` → `start()` → ... →
|
|
14
|
+
* `stop()` (idempotent) or `shutdown()` (final teardown). Subscribe to
|
|
15
|
+
* `onState` / `onPosition` for live updates; query `history(from, to)` for
|
|
16
|
+
* persisted points.
|
|
17
|
+
*
|
|
18
|
+
* **Threading:** Methods are safe to call from any JS context. Subscribers'
|
|
19
|
+
* callbacks fire on the JS thread.
|
|
20
|
+
*
|
|
21
|
+
* **Persistence invariant:** the SDK persists every gated position natively;
|
|
22
|
+
* JS is a passive observer. In background, the JS engine is not guaranteed to
|
|
23
|
+
* be alive — for past points, use `history()`.
|
|
24
|
+
*/
|
|
25
|
+
class BeekonImpl {
|
|
26
|
+
/**
|
|
27
|
+
* Initialize the SDK. Idempotent; safe to call more than once. Must be
|
|
28
|
+
* called once before `configure()`.
|
|
29
|
+
*
|
|
30
|
+
* Errors:
|
|
31
|
+
* - `NO_GMS_AVAILABLE` (Android) — Google Play Services missing.
|
|
32
|
+
*/
|
|
33
|
+
async init(): Promise<void> {
|
|
34
|
+
return NativeBeekon.initialize();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/**
|
|
38
|
+
* Set sampling and platform-specific config. Replaces any previous config.
|
|
39
|
+
* Must be called before `start()`.
|
|
40
|
+
*
|
|
41
|
+
* Errors:
|
|
42
|
+
* - `NOT_INITIALISED` — `init()` was not called first.
|
|
43
|
+
* - `NOT_CONFIGURED` — Android only, `androidNotification` was missing.
|
|
44
|
+
*/
|
|
45
|
+
async configure(config: BeekonConfig): Promise<void> {
|
|
46
|
+
return NativeBeekon.configure(configToWire(config));
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/**
|
|
50
|
+
* Begin tracking. Transitions state from `idle` → `starting` → `tracking`.
|
|
51
|
+
*
|
|
52
|
+
* Errors:
|
|
53
|
+
* - `PERMISSION_DENIED` — location permission not granted.
|
|
54
|
+
* - `LOCATION_SERVICES_DISABLED` (iOS) — system location services off.
|
|
55
|
+
* - `SERVICE_FAILED` — native service couldn't start.
|
|
56
|
+
*/
|
|
57
|
+
async start(): Promise<void> {
|
|
58
|
+
return NativeBeekon.start();
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/** Stop tracking. Idempotent. State → `stopped`. */
|
|
62
|
+
async stop(): Promise<void> {
|
|
63
|
+
return NativeBeekon.stop();
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Final teardown — releases native resources. Most apps don't need this;
|
|
68
|
+
* `stop()` is sufficient between sessions.
|
|
69
|
+
*/
|
|
70
|
+
async shutdown(): Promise<void> {
|
|
71
|
+
return NativeBeekon.shutdown();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Read persisted positions in the time range [from, to]. Returns positions
|
|
76
|
+
* in chronological order. Reads come from the SDK's local storage (Room on
|
|
77
|
+
* Android, GRDB on iOS) — the source of truth even when JS was asleep.
|
|
78
|
+
*
|
|
79
|
+
* Retention: positions older than 7 days OR beyond the most recent 100K are
|
|
80
|
+
* pruned automatically.
|
|
81
|
+
*/
|
|
82
|
+
async history(from: Date, to: Date): Promise<Position[]> {
|
|
83
|
+
const wires = await NativeBeekon.history(from.getTime(), to.getTime());
|
|
84
|
+
return wires.map(wireToPosition);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Subscribe to state transitions. Returns an unsubscribe function. The
|
|
89
|
+
* current state is delivered to new subscribers immediately (replay-1
|
|
90
|
+
* semantics, matching the native `state` flow).
|
|
91
|
+
*/
|
|
92
|
+
onState(cb: (s: BeekonState) => void): () => void {
|
|
93
|
+
const subscription = NativeBeekon.onState((wire) => cb(wireToState(wire)));
|
|
94
|
+
return () => subscription.remove();
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
/**
|
|
98
|
+
* Subscribe to gated positions as they arrive. Returns an unsubscribe
|
|
99
|
+
* function. Broadcast (no replay) — only delivers while the JS engine is
|
|
100
|
+
* alive. For points emitted while JS was asleep, use `history()`.
|
|
101
|
+
*/
|
|
102
|
+
onPosition(cb: (p: Position) => void): () => void {
|
|
103
|
+
const subscription = NativeBeekon.onPosition((wire) =>
|
|
104
|
+
cb(wireToPosition(wire))
|
|
105
|
+
);
|
|
106
|
+
return () => subscription.remove();
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export const Beekon = new BeekonImpl();
|
package/src/index.tsx
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export { Beekon } from './beekon';
|
|
2
|
+
export type { BeekonConfig, AndroidNotificationConfig } from './types/config';
|
|
3
|
+
export type { Preset } from './types/preset';
|
|
4
|
+
export type { BeekonState, PauseReason } from './types/state';
|
|
5
|
+
export type { Position } from './types/position';
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { BeekonConfig } from '../types/config';
|
|
2
|
+
import type { BeekonState, PauseReason } from '../types/state';
|
|
3
|
+
import type { Position } from '../types/position';
|
|
4
|
+
import type { WireConfig, WirePosition, WireState } from '../NativeBeekonRn';
|
|
5
|
+
|
|
6
|
+
export function configToWire(config: BeekonConfig): WireConfig {
|
|
7
|
+
return {
|
|
8
|
+
preset: config.preset ?? 'balanced',
|
|
9
|
+
distanceFilterMeters: config.distanceFilterMeters,
|
|
10
|
+
intervalMillis: config.intervalMillis,
|
|
11
|
+
androidNotification: config.androidNotification,
|
|
12
|
+
licenseKey: config.licenseKey,
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
export function wireToPosition(w: WirePosition): Position {
|
|
17
|
+
return {
|
|
18
|
+
lat: w.lat,
|
|
19
|
+
lng: w.lng,
|
|
20
|
+
accuracy: w.accuracy,
|
|
21
|
+
speed: w.speed,
|
|
22
|
+
bearing: w.bearing,
|
|
23
|
+
altitude: w.altitude,
|
|
24
|
+
timestamp: new Date(w.timestampMs),
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
function toPauseReason(s: string | undefined): PauseReason {
|
|
29
|
+
if (s === 'permissionRevoked' || s === 'locationDisabled') return s;
|
|
30
|
+
return 'unknown';
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export function wireToState(w: WireState): BeekonState {
|
|
34
|
+
switch (w.type) {
|
|
35
|
+
case 'idle':
|
|
36
|
+
return { kind: 'idle' };
|
|
37
|
+
case 'starting':
|
|
38
|
+
return { kind: 'starting' };
|
|
39
|
+
case 'tracking':
|
|
40
|
+
return { kind: 'tracking' };
|
|
41
|
+
case 'paused':
|
|
42
|
+
return { kind: 'paused', reason: toPauseReason(w.pauseReason) };
|
|
43
|
+
case 'stopped':
|
|
44
|
+
return { kind: 'stopped' };
|
|
45
|
+
default:
|
|
46
|
+
// Defensive fallback. Native should never emit an unknown state, but
|
|
47
|
+
// forward-compat: treat as idle rather than throwing.
|
|
48
|
+
return { kind: 'idle' };
|
|
49
|
+
}
|
|
50
|
+
}
|