@wayq/beekon-rn 0.1.0 → 0.1.2
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/CHANGELOG.md +41 -0
- package/README.md +28 -2
- package/android/build.gradle +1 -1
- package/android/src/main/AndroidManifest.xml +10 -0
- package/android/src/main/java/in/wayq/beekonrn/BeekonRnModule.kt +105 -1
- package/ios/BeekonRn.swift +60 -10
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/BeekonKit +0 -0
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.abi.json +5472 -2309
- 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 +87 -3
- 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/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.abi.json +5472 -2309
- 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 +87 -3
- package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.abi.json +5472 -2309
- 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 +87 -3
- package/lib/module/NativeBeekonRn.js +8 -0
- package/lib/module/NativeBeekonRn.js.map +1 -1
- package/lib/module/beekon.js +14 -1
- package/lib/module/beekon.js.map +1 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/internal/mappers.js +83 -2
- package/lib/module/internal/mappers.js.map +1 -1
- package/lib/typescript/src/NativeBeekonRn.d.ts +20 -0
- package/lib/typescript/src/NativeBeekonRn.d.ts.map +1 -1
- package/lib/typescript/src/beekon.d.ts +11 -1
- package/lib/typescript/src/beekon.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +2 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/internal/mappers.d.ts +3 -2
- package/lib/typescript/src/internal/mappers.d.ts.map +1 -1
- package/lib/typescript/src/types/geofence.d.ts +37 -0
- package/lib/typescript/src/types/geofence.d.ts.map +1 -1
- package/lib/typescript/src/types/permission.d.ts +36 -0
- package/lib/typescript/src/types/permission.d.ts.map +1 -1
- package/package.json +1 -1
- package/scripts/fetch-beekonkit.sh +4 -4
- package/src/NativeBeekonRn.ts +24 -0
- package/src/beekon.ts +20 -1
- package/src/index.tsx +7 -0
- package/src/internal/mappers.ts +114 -0
- package/src/types/geofence.ts +41 -0
- package/src/types/permission.ts +43 -0
|
@@ -16,6 +16,43 @@ export type BeekonGeofence = {
|
|
|
16
16
|
notifyOnEntry?: boolean;
|
|
17
17
|
/** Emit an event on exit. Default: `true`. */
|
|
18
18
|
notifyOnExit?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Optional per-geofence notification the SDK renders natively at crossing time —
|
|
21
|
+
* offline and even when the app is killed. Omit it to handle crossings yourself
|
|
22
|
+
* via `Beekon.onGeofenceEvent`. `onEnter` requires `notifyOnEntry`; `onExit`
|
|
23
|
+
* requires `notifyOnExit`; in self-managed mode `delivery` must be `'local'`.
|
|
24
|
+
*/
|
|
25
|
+
notification?: GeofenceNotification;
|
|
26
|
+
};
|
|
27
|
+
/** Where a geofence-crossing notification is delivered. Mirrors `NotificationDelivery` on the natives. */
|
|
28
|
+
export type NotificationDelivery = 'local' | 'cloud';
|
|
29
|
+
/** Relative prominence of a geofence notification. Mirrors `NotificationImportance`. */
|
|
30
|
+
export type NotificationImportance = 'high' | 'default';
|
|
31
|
+
/** Per-direction content the SDK renders natively for a geofence crossing. */
|
|
32
|
+
export type NotificationContent = {
|
|
33
|
+
/** Notification title. */
|
|
34
|
+
title: string;
|
|
35
|
+
/** Notification body. */
|
|
36
|
+
body: string;
|
|
37
|
+
/** Relative prominence. Default `'high'`. */
|
|
38
|
+
importance?: NotificationImportance;
|
|
39
|
+
/** Optional deep-link URI delivered in the notification for the host to route on tap. */
|
|
40
|
+
deepLink?: string;
|
|
41
|
+
/** Optional flat string payload delivered in the notification for routing on tap. */
|
|
42
|
+
data?: Record<string, string>;
|
|
43
|
+
};
|
|
44
|
+
/**
|
|
45
|
+
* An optional per-geofence notification rendered natively at crossing time.
|
|
46
|
+
* Mirrors `GeofenceNotification` on both native SDKs. The presence of `onEnter` /
|
|
47
|
+
* `onExit` selects which directions notify.
|
|
48
|
+
*/
|
|
49
|
+
export type GeofenceNotification = {
|
|
50
|
+
/** Delivery channel. `'local'` (offline, device-rendered) is the default and only implemented mode. */
|
|
51
|
+
delivery: NotificationDelivery;
|
|
52
|
+
/** Content rendered on entry. Requires `notifyOnEntry`. */
|
|
53
|
+
onEnter?: NotificationContent;
|
|
54
|
+
/** Content rendered on exit. Requires `notifyOnExit`. */
|
|
55
|
+
onExit?: NotificationContent;
|
|
19
56
|
};
|
|
20
57
|
/** Whether a {@link GeofenceEvent} marks entering or exiting a geofence. */
|
|
21
58
|
export type Transition = 'enter' | 'exit';
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"geofence.d.ts","sourceRoot":"","sources":["../../../../src/types/geofence.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,yEAAyE;IACzE,EAAE,EAAE,MAAM,CAAC;IACX,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,YAAY,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,8CAA8C;IAC9C,YAAY,CAAC,EAAE,OAAO,CAAC;
|
|
1
|
+
{"version":3,"file":"geofence.d.ts","sourceRoot":"","sources":["../../../../src/types/geofence.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,yEAAyE;IACzE,EAAE,EAAE,MAAM,CAAC;IACX,0CAA0C;IAC1C,QAAQ,EAAE,MAAM,CAAC;IACjB,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,gFAAgF;IAChF,YAAY,EAAE,MAAM,CAAC;IACrB,+CAA+C;IAC/C,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,8CAA8C;IAC9C,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB;;;;;OAKG;IACH,YAAY,CAAC,EAAE,oBAAoB,CAAC;CACrC,CAAC;AAEF,0GAA0G;AAC1G,MAAM,MAAM,oBAAoB,GAAG,OAAO,GAAG,OAAO,CAAC;AAErD,wFAAwF;AACxF,MAAM,MAAM,sBAAsB,GAAG,MAAM,GAAG,SAAS,CAAC;AAExD,8EAA8E;AAC9E,MAAM,MAAM,mBAAmB,GAAG;IAChC,0BAA0B;IAC1B,KAAK,EAAE,MAAM,CAAC;IACd,yBAAyB;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,6CAA6C;IAC7C,UAAU,CAAC,EAAE,sBAAsB,CAAC;IACpC,yFAAyF;IACzF,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qFAAqF;IACrF,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC/B,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,oBAAoB,GAAG;IACjC,uGAAuG;IACvG,QAAQ,EAAE,oBAAoB,CAAC;IAC/B,2DAA2D;IAC3D,OAAO,CAAC,EAAE,mBAAmB,CAAC;IAC9B,yDAAyD;IACzD,MAAM,CAAC,EAAE,mBAAmB,CAAC;CAC9B,CAAC;AAEF,4EAA4E;AAC5E,MAAM,MAAM,UAAU,GAAG,OAAO,GAAG,MAAM,CAAC;AAE1C;;;GAGG;AACH,MAAM,MAAM,aAAa,GAAG;IAC1B,wDAAwD;IACxD,EAAE,EAAE,MAAM,CAAC;IACX,sDAAsD;IACtD,UAAU,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,IAAI,EAAE,UAAU,CAAC;IACjB,kCAAkC;IAClC,SAAS,EAAE,IAAI,CAAC;CACjB,CAAC"}
|
|
@@ -39,4 +39,40 @@ export type PermissionStatus = {
|
|
|
39
39
|
/** `true` when background tracking is authorized. */
|
|
40
40
|
canTrackInBackground: boolean;
|
|
41
41
|
};
|
|
42
|
+
/**
|
|
43
|
+
* A permission Beekon may require, normalized across platforms. Mirrors the
|
|
44
|
+
* native `BeekonPermission`.
|
|
45
|
+
*
|
|
46
|
+
* - `'location'` — foreground location; required for all tracking.
|
|
47
|
+
* - `'backgroundLocation'` — background revival, geofences, stationary resume.
|
|
48
|
+
* - `'activityRecognition'` — motion-based stationary detection.
|
|
49
|
+
* - `'notifications'` — the foreground-service notification (**Android only**).
|
|
50
|
+
*/
|
|
51
|
+
export type BeekonPermission = 'location' | 'backgroundLocation' | 'activityRecognition' | 'notifications';
|
|
52
|
+
/**
|
|
53
|
+
* How badly a {@link PermissionRequirement} is needed.
|
|
54
|
+
*
|
|
55
|
+
* - `'required'` — tracking cannot start, or an explicitly-enabled feature is dead, without it.
|
|
56
|
+
* - `'recommended'` — an active feature silently degrades without it; tracking still runs.
|
|
57
|
+
*/
|
|
58
|
+
export type PermissionImportance = 'required' | 'recommended';
|
|
59
|
+
/**
|
|
60
|
+
* One permission Beekon needs **for the current configuration**, each marked
|
|
61
|
+
* satisfied against the live grant — returned by `Beekon.getRequiredPermissions()`.
|
|
62
|
+
* Mirrors the native `PermissionRequirement`.
|
|
63
|
+
*
|
|
64
|
+
* Beekon never *requests* permission — the app owns that. This is the
|
|
65
|
+
* config-aware "doctor" companion to {@link PermissionStatus}: it reports
|
|
66
|
+
* activity-recognition (and, on Android, notifications) too.
|
|
67
|
+
*/
|
|
68
|
+
export type PermissionRequirement = {
|
|
69
|
+
/** The normalized permission. */
|
|
70
|
+
permission: BeekonPermission;
|
|
71
|
+
/** Whether tracking/a feature breaks (`'required'`) or merely degrades (`'recommended'`) when absent. */
|
|
72
|
+
importance: PermissionImportance;
|
|
73
|
+
/** Whether the live OS grant covers it right now. */
|
|
74
|
+
satisfied: boolean;
|
|
75
|
+
/** Human-readable explanation of why Beekon needs it / what degrades without it. */
|
|
76
|
+
rationale: string;
|
|
77
|
+
};
|
|
42
78
|
//# sourceMappingURL=permission.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"permission.d.ts","sourceRoot":"","sources":["../../../../src/types/permission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,eAAe,GACvB,eAAe,GACf,QAAQ,GACR,YAAY,GACZ,YAAY,GACZ,YAAY,CAAC;AAEjB;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,SAAS,CAAC;AAEpD;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,iCAAiC;IACjC,KAAK,EAAE,eAAe,CAAC;IACvB,6DAA6D;IAC7D,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACpC,gEAAgE;IAChE,YAAY,EAAE,OAAO,CAAC;IACtB,qDAAqD;IACrD,oBAAoB,EAAE,OAAO,CAAC;CAC/B,CAAC"}
|
|
1
|
+
{"version":3,"file":"permission.d.ts","sourceRoot":"","sources":["../../../../src/types/permission.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AACH,MAAM,MAAM,eAAe,GACvB,eAAe,GACf,QAAQ,GACR,YAAY,GACZ,YAAY,GACZ,YAAY,CAAC;AAEjB;;;;;GAKG;AACH,MAAM,MAAM,kBAAkB,GAAG,MAAM,GAAG,SAAS,CAAC;AAEpD;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,iCAAiC;IACjC,KAAK,EAAE,eAAe,CAAC;IACvB,6DAA6D;IAC7D,QAAQ,EAAE,kBAAkB,GAAG,IAAI,CAAC;IACpC,gEAAgE;IAChE,YAAY,EAAE,OAAO,CAAC;IACtB,qDAAqD;IACrD,oBAAoB,EAAE,OAAO,CAAC;CAC/B,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,MAAM,gBAAgB,GACxB,UAAU,GACV,oBAAoB,GACpB,qBAAqB,GACrB,eAAe,CAAC;AAEpB;;;;;GAKG;AACH,MAAM,MAAM,oBAAoB,GAAG,UAAU,GAAG,aAAa,CAAC;AAE9D;;;;;;;;GAQG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,iCAAiC;IACjC,UAAU,EAAE,gBAAgB,CAAC;IAC7B,yGAAyG;IACzG,UAAU,EAAE,oBAAoB,CAAC;IACjC,qDAAqD;IACrD,SAAS,EAAE,OAAO,CAAC;IACnB,oFAAoF;IACpF,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC"}
|
package/package.json
CHANGED
|
@@ -13,12 +13,12 @@
|
|
|
13
13
|
|
|
14
14
|
set -euo pipefail
|
|
15
15
|
|
|
16
|
-
VERSION="0.1.
|
|
16
|
+
VERSION="0.1.2"
|
|
17
17
|
URL="https://github.com/beekonlabs/beekon-ios-binary/releases/download/v${VERSION}/BeekonKit.xcframework.zip"
|
|
18
|
-
# SHA256 of the v0.
|
|
19
|
-
# `binaryTarget` checksum in beekon-ios-binary's Package.swift at tag v0.
|
|
18
|
+
# SHA256 of the v0.1.2 BeekonKit.xcframework.zip. Matches the SwiftPM
|
|
19
|
+
# `binaryTarget` checksum in beekon-ios-binary's Package.swift at tag v0.1.2
|
|
20
20
|
# (SwiftPM's compute-checksum is the SHA256 of the zip).
|
|
21
|
-
EXPECTED_SHA="
|
|
21
|
+
EXPECTED_SHA="43b1f959699654020f32d3e8e4e1de6aacba8e32628c69a7477c1b2ba084a4a4"
|
|
22
22
|
|
|
23
23
|
ROOT="$(cd "$(dirname "$0")/.." && pwd)"
|
|
24
24
|
DEST_DIR="${ROOT}/ios/Frameworks"
|
package/src/NativeBeekonRn.ts
CHANGED
|
@@ -156,6 +156,9 @@ export type WireGeofence = {
|
|
|
156
156
|
radiusMeters: number;
|
|
157
157
|
notifyOnEntry: boolean;
|
|
158
158
|
notifyOnExit: boolean;
|
|
159
|
+
// Optional notification as a canonical JSON string (rendering is native-only).
|
|
160
|
+
// Flat string keeps Codegen happy and lets the payload schema grow without re-running codegen.
|
|
161
|
+
notificationJson?: string;
|
|
159
162
|
};
|
|
160
163
|
|
|
161
164
|
export type WireGeofenceEvent = {
|
|
@@ -233,6 +236,20 @@ export type WirePermissionStatus = {
|
|
|
233
236
|
accuracy: string;
|
|
234
237
|
};
|
|
235
238
|
|
|
239
|
+
/**
|
|
240
|
+
* Flat wire form of one `PermissionRequirement` (read-only). `permission` is one
|
|
241
|
+
* of 'location' | 'backgroundLocation' | 'activityRecognition' | 'notifications'
|
|
242
|
+
* ('notifications' Android-only); `importance` is 'required' | 'recommended'.
|
|
243
|
+
* The mappers translate to the public string-literal unions with a defensive
|
|
244
|
+
* fallback.
|
|
245
|
+
*/
|
|
246
|
+
export type WirePermissionRequirement = {
|
|
247
|
+
permission: string;
|
|
248
|
+
importance: string;
|
|
249
|
+
satisfied: boolean;
|
|
250
|
+
rationale: string;
|
|
251
|
+
};
|
|
252
|
+
|
|
236
253
|
export interface Spec extends TurboModule {
|
|
237
254
|
/**
|
|
238
255
|
* The config crosses as an untyped object (`ReadableMap` on Android,
|
|
@@ -288,6 +305,13 @@ export interface Spec extends TurboModule {
|
|
|
288
305
|
*/
|
|
289
306
|
getPermissionStatus(): Promise<WirePermissionStatus>;
|
|
290
307
|
|
|
308
|
+
/**
|
|
309
|
+
* The permissions Beekon needs for the active configuration, each marked
|
|
310
|
+
* satisfied against the live grant (read-only; never prompts). The config-aware
|
|
311
|
+
* companion to `getPermissionStatus`. Call after `configure`.
|
|
312
|
+
*/
|
|
313
|
+
getRequiredPermissions(): Promise<WirePermissionRequirement[]>;
|
|
314
|
+
|
|
291
315
|
/** Persisted diagnostic log entries in `[fromMs, toMs]`, oldest first. */
|
|
292
316
|
getLog(fromMs: number, toMs: number): Promise<WireLogEntry[]>;
|
|
293
317
|
/** Serialize the whole log buffer to an NDJSON file; resolves its path. */
|
package/src/beekon.ts
CHANGED
|
@@ -7,7 +7,10 @@ import type { BeekonGeofence, GeofenceEvent } from './types/geofence';
|
|
|
7
7
|
import type { LicenseStatus } from './types/license';
|
|
8
8
|
import type { Location } from './types/location';
|
|
9
9
|
import type { LogEntry } from './types/log';
|
|
10
|
-
import type {
|
|
10
|
+
import type {
|
|
11
|
+
PermissionRequirement,
|
|
12
|
+
PermissionStatus,
|
|
13
|
+
} from './types/permission';
|
|
11
14
|
import type { BeekonState } from './types/state';
|
|
12
15
|
import type { SyncStatus } from './types/sync';
|
|
13
16
|
import {
|
|
@@ -21,6 +24,7 @@ import {
|
|
|
21
24
|
wireToLicenseStatus,
|
|
22
25
|
wireToLocation,
|
|
23
26
|
wireToLogEntry,
|
|
27
|
+
wireToPermissionRequirement,
|
|
24
28
|
wireToPermissionStatus,
|
|
25
29
|
wireToState,
|
|
26
30
|
wireToSyncStatus,
|
|
@@ -368,6 +372,21 @@ class BeekonImpl {
|
|
|
368
372
|
return wireToPermissionStatus(await NativeBeekon.getPermissionStatus());
|
|
369
373
|
}
|
|
370
374
|
|
|
375
|
+
/**
|
|
376
|
+
* The permissions Beekon needs **for the current configuration**, each marked
|
|
377
|
+
* `satisfied` against the live grant — the config-aware "doctor" companion to
|
|
378
|
+
* `getPermissionStatus()`. Unlike that location-only snapshot, this reports
|
|
379
|
+
* activity-recognition (and, on Android, notifications) too, derived from the
|
|
380
|
+
* active mode and tracking config. Read-only; never prompts. Call after
|
|
381
|
+
* `configure()`; in cloud mode (server-owned config) it returns the
|
|
382
|
+
* conservative list.
|
|
383
|
+
*/
|
|
384
|
+
async getRequiredPermissions(): Promise<PermissionRequirement[]> {
|
|
385
|
+
return (await NativeBeekon.getRequiredPermissions()).map(
|
|
386
|
+
wireToPermissionRequirement
|
|
387
|
+
);
|
|
388
|
+
}
|
|
389
|
+
|
|
371
390
|
/**
|
|
372
391
|
* Read persisted diagnostic log entries in the inclusive range `[from, to]`,
|
|
373
392
|
* oldest first. Entries survive process death, so this recovers what the SDK
|
package/src/index.tsx
CHANGED
|
@@ -26,6 +26,10 @@ export type { Location } from './types/location';
|
|
|
26
26
|
export type {
|
|
27
27
|
BeekonGeofence,
|
|
28
28
|
GeofenceEvent,
|
|
29
|
+
GeofenceNotification,
|
|
30
|
+
NotificationContent,
|
|
31
|
+
NotificationDelivery,
|
|
32
|
+
NotificationImportance,
|
|
29
33
|
Transition,
|
|
30
34
|
} from './types/geofence';
|
|
31
35
|
export type { BeekonState, StopReason } from './types/state';
|
|
@@ -33,6 +37,9 @@ export type {
|
|
|
33
37
|
PermissionStatus,
|
|
34
38
|
PermissionLevel,
|
|
35
39
|
PermissionAccuracy,
|
|
40
|
+
BeekonPermission,
|
|
41
|
+
PermissionImportance,
|
|
42
|
+
PermissionRequirement,
|
|
36
43
|
} from './types/permission';
|
|
37
44
|
export type { SyncStatus, SyncFailure } from './types/sync';
|
|
38
45
|
export type { LicenseStatus, LicenseInvalidReason } from './types/license';
|
package/src/internal/mappers.ts
CHANGED
|
@@ -15,13 +15,20 @@ import type { LogEntry } from '../types/log';
|
|
|
15
15
|
import type {
|
|
16
16
|
BeekonGeofence,
|
|
17
17
|
GeofenceEvent,
|
|
18
|
+
GeofenceNotification,
|
|
19
|
+
NotificationContent,
|
|
20
|
+
NotificationDelivery,
|
|
21
|
+
NotificationImportance,
|
|
18
22
|
Transition,
|
|
19
23
|
} from '../types/geofence';
|
|
20
24
|
import type { LicenseInvalidReason, LicenseStatus } from '../types/license';
|
|
21
25
|
import type { Location } from '../types/location';
|
|
22
26
|
import type {
|
|
27
|
+
BeekonPermission,
|
|
23
28
|
PermissionAccuracy,
|
|
29
|
+
PermissionImportance,
|
|
24
30
|
PermissionLevel,
|
|
31
|
+
PermissionRequirement,
|
|
25
32
|
PermissionStatus,
|
|
26
33
|
} from '../types/permission';
|
|
27
34
|
import type { BeekonState, StopReason } from '../types/state';
|
|
@@ -37,6 +44,7 @@ import type {
|
|
|
37
44
|
WireLicenseStatus,
|
|
38
45
|
WireLocation,
|
|
39
46
|
WireLogEntry,
|
|
47
|
+
WirePermissionRequirement,
|
|
40
48
|
WirePermissionStatus,
|
|
41
49
|
WireState,
|
|
42
50
|
WireSyncStatus,
|
|
@@ -158,9 +166,90 @@ export function geofenceToWire(g: BeekonGeofence): WireGeofence {
|
|
|
158
166
|
radiusMeters: g.radiusMeters,
|
|
159
167
|
notifyOnEntry: g.notifyOnEntry ?? true,
|
|
160
168
|
notifyOnExit: g.notifyOnExit ?? true,
|
|
169
|
+
notificationJson: notificationToJson(g.notification),
|
|
161
170
|
};
|
|
162
171
|
}
|
|
163
172
|
|
|
173
|
+
// Serialize a notification to the canonical JSON string the native SDKs understand
|
|
174
|
+
// (rendering is native-only). Optional keys are omitted; undefined ⇒ undefined.
|
|
175
|
+
function notificationToJson(
|
|
176
|
+
n: GeofenceNotification | undefined
|
|
177
|
+
): string | undefined {
|
|
178
|
+
if (!n) return undefined;
|
|
179
|
+
const obj: Record<string, unknown> = {
|
|
180
|
+
delivery: n.delivery === 'cloud' ? 'cloud' : 'local',
|
|
181
|
+
};
|
|
182
|
+
if (n.onEnter) obj.onEnter = contentToObj(n.onEnter);
|
|
183
|
+
if (n.onExit) obj.onExit = contentToObj(n.onExit);
|
|
184
|
+
return JSON.stringify(obj);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function contentToObj(c: NotificationContent): Record<string, unknown> {
|
|
188
|
+
const obj: Record<string, unknown> = {
|
|
189
|
+
title: c.title,
|
|
190
|
+
body: c.body,
|
|
191
|
+
importance: c.importance === 'default' ? 'default' : 'high',
|
|
192
|
+
};
|
|
193
|
+
if (c.deepLink != null) obj.deepLink = c.deepLink;
|
|
194
|
+
if (c.data && Object.keys(c.data).length > 0) obj.data = c.data;
|
|
195
|
+
return obj;
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Parse a canonical notification JSON string. Tolerant: malformed input, an unknown
|
|
199
|
+
// enum, or content missing title/body degrades to undefined/defaults.
|
|
200
|
+
function notificationFromJson(
|
|
201
|
+
json: string | undefined
|
|
202
|
+
): GeofenceNotification | undefined {
|
|
203
|
+
if (!json) return undefined;
|
|
204
|
+
let parsed: unknown;
|
|
205
|
+
try {
|
|
206
|
+
parsed = JSON.parse(json);
|
|
207
|
+
} catch {
|
|
208
|
+
return undefined;
|
|
209
|
+
}
|
|
210
|
+
if (typeof parsed !== 'object' || parsed === null) return undefined;
|
|
211
|
+
const obj = parsed as Record<string, unknown>;
|
|
212
|
+
const onEnter = contentFromObj(obj.onEnter);
|
|
213
|
+
const onExit = contentFromObj(obj.onExit);
|
|
214
|
+
if (!onEnter && !onExit) return undefined;
|
|
215
|
+
const delivery: NotificationDelivery =
|
|
216
|
+
obj.delivery === 'cloud' ? 'cloud' : 'local';
|
|
217
|
+
return {
|
|
218
|
+
delivery,
|
|
219
|
+
...(onEnter ? { onEnter } : {}),
|
|
220
|
+
...(onExit ? { onExit } : {}),
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
function contentFromObj(raw: unknown): NotificationContent | undefined {
|
|
225
|
+
if (typeof raw !== 'object' || raw === null) return undefined;
|
|
226
|
+
const r = raw as Record<string, unknown>;
|
|
227
|
+
if (
|
|
228
|
+
typeof r.title !== 'string' ||
|
|
229
|
+
typeof r.body !== 'string' ||
|
|
230
|
+
!r.title ||
|
|
231
|
+
!r.body
|
|
232
|
+
) {
|
|
233
|
+
return undefined;
|
|
234
|
+
}
|
|
235
|
+
const importance: NotificationImportance =
|
|
236
|
+
r.importance === 'default' ? 'default' : 'high';
|
|
237
|
+
const data: Record<string, string> = {};
|
|
238
|
+
if (typeof r.data === 'object' && r.data !== null) {
|
|
239
|
+
for (const [k, v] of Object.entries(r.data as Record<string, unknown>)) {
|
|
240
|
+
if (typeof v === 'string') data[k] = v;
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
const content: NotificationContent = {
|
|
244
|
+
title: r.title,
|
|
245
|
+
body: r.body,
|
|
246
|
+
importance,
|
|
247
|
+
};
|
|
248
|
+
if (typeof r.deepLink === 'string') content.deepLink = r.deepLink;
|
|
249
|
+
if (Object.keys(data).length > 0) content.data = data;
|
|
250
|
+
return content;
|
|
251
|
+
}
|
|
252
|
+
|
|
164
253
|
// `expiresAt` (a `Date`) becomes epoch millis on the wire; the native side
|
|
165
254
|
// converts to epoch seconds. String maps travel as `WireKeyValue[]`.
|
|
166
255
|
export function authToWire(a: AuthConfig): WireAuthConfig {
|
|
@@ -240,6 +329,7 @@ export function wireToGeofence(w: WireGeofence): BeekonGeofence {
|
|
|
240
329
|
radiusMeters: w.radiusMeters,
|
|
241
330
|
notifyOnEntry: w.notifyOnEntry,
|
|
242
331
|
notifyOnExit: w.notifyOnExit,
|
|
332
|
+
notification: notificationFromJson(w.notificationJson),
|
|
243
333
|
};
|
|
244
334
|
}
|
|
245
335
|
|
|
@@ -300,6 +390,30 @@ export function wireToPermissionStatus(
|
|
|
300
390
|
};
|
|
301
391
|
}
|
|
302
392
|
|
|
393
|
+
export function wireToPermissionRequirement(
|
|
394
|
+
w: WirePermissionRequirement
|
|
395
|
+
): PermissionRequirement {
|
|
396
|
+
return {
|
|
397
|
+
permission: oneOf<BeekonPermission>(
|
|
398
|
+
w.permission,
|
|
399
|
+
[
|
|
400
|
+
'location',
|
|
401
|
+
'backgroundLocation',
|
|
402
|
+
'activityRecognition',
|
|
403
|
+
'notifications',
|
|
404
|
+
],
|
|
405
|
+
'location'
|
|
406
|
+
),
|
|
407
|
+
importance: oneOf<PermissionImportance>(
|
|
408
|
+
w.importance,
|
|
409
|
+
['required', 'recommended'],
|
|
410
|
+
'recommended'
|
|
411
|
+
),
|
|
412
|
+
satisfied: w.satisfied,
|
|
413
|
+
rationale: w.rationale,
|
|
414
|
+
};
|
|
415
|
+
}
|
|
416
|
+
|
|
303
417
|
export function wireToSyncStatus(w: WireSyncStatus): SyncStatus {
|
|
304
418
|
switch (w.type) {
|
|
305
419
|
case 'idle':
|
package/src/types/geofence.ts
CHANGED
|
@@ -16,6 +16,47 @@ export type BeekonGeofence = {
|
|
|
16
16
|
notifyOnEntry?: boolean;
|
|
17
17
|
/** Emit an event on exit. Default: `true`. */
|
|
18
18
|
notifyOnExit?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Optional per-geofence notification the SDK renders natively at crossing time —
|
|
21
|
+
* offline and even when the app is killed. Omit it to handle crossings yourself
|
|
22
|
+
* via `Beekon.onGeofenceEvent`. `onEnter` requires `notifyOnEntry`; `onExit`
|
|
23
|
+
* requires `notifyOnExit`; in self-managed mode `delivery` must be `'local'`.
|
|
24
|
+
*/
|
|
25
|
+
notification?: GeofenceNotification;
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
/** Where a geofence-crossing notification is delivered. Mirrors `NotificationDelivery` on the natives. */
|
|
29
|
+
export type NotificationDelivery = 'local' | 'cloud';
|
|
30
|
+
|
|
31
|
+
/** Relative prominence of a geofence notification. Mirrors `NotificationImportance`. */
|
|
32
|
+
export type NotificationImportance = 'high' | 'default';
|
|
33
|
+
|
|
34
|
+
/** Per-direction content the SDK renders natively for a geofence crossing. */
|
|
35
|
+
export type NotificationContent = {
|
|
36
|
+
/** Notification title. */
|
|
37
|
+
title: string;
|
|
38
|
+
/** Notification body. */
|
|
39
|
+
body: string;
|
|
40
|
+
/** Relative prominence. Default `'high'`. */
|
|
41
|
+
importance?: NotificationImportance;
|
|
42
|
+
/** Optional deep-link URI delivered in the notification for the host to route on tap. */
|
|
43
|
+
deepLink?: string;
|
|
44
|
+
/** Optional flat string payload delivered in the notification for routing on tap. */
|
|
45
|
+
data?: Record<string, string>;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* An optional per-geofence notification rendered natively at crossing time.
|
|
50
|
+
* Mirrors `GeofenceNotification` on both native SDKs. The presence of `onEnter` /
|
|
51
|
+
* `onExit` selects which directions notify.
|
|
52
|
+
*/
|
|
53
|
+
export type GeofenceNotification = {
|
|
54
|
+
/** Delivery channel. `'local'` (offline, device-rendered) is the default and only implemented mode. */
|
|
55
|
+
delivery: NotificationDelivery;
|
|
56
|
+
/** Content rendered on entry. Requires `notifyOnEntry`. */
|
|
57
|
+
onEnter?: NotificationContent;
|
|
58
|
+
/** Content rendered on exit. Requires `notifyOnExit`. */
|
|
59
|
+
onExit?: NotificationContent;
|
|
19
60
|
};
|
|
20
61
|
|
|
21
62
|
/** Whether a {@link GeofenceEvent} marks entering or exiting a geofence. */
|
package/src/types/permission.ts
CHANGED
|
@@ -46,3 +46,46 @@ export type PermissionStatus = {
|
|
|
46
46
|
/** `true` when background tracking is authorized. */
|
|
47
47
|
canTrackInBackground: boolean;
|
|
48
48
|
};
|
|
49
|
+
|
|
50
|
+
/**
|
|
51
|
+
* A permission Beekon may require, normalized across platforms. Mirrors the
|
|
52
|
+
* native `BeekonPermission`.
|
|
53
|
+
*
|
|
54
|
+
* - `'location'` — foreground location; required for all tracking.
|
|
55
|
+
* - `'backgroundLocation'` — background revival, geofences, stationary resume.
|
|
56
|
+
* - `'activityRecognition'` — motion-based stationary detection.
|
|
57
|
+
* - `'notifications'` — the foreground-service notification (**Android only**).
|
|
58
|
+
*/
|
|
59
|
+
export type BeekonPermission =
|
|
60
|
+
| 'location'
|
|
61
|
+
| 'backgroundLocation'
|
|
62
|
+
| 'activityRecognition'
|
|
63
|
+
| 'notifications';
|
|
64
|
+
|
|
65
|
+
/**
|
|
66
|
+
* How badly a {@link PermissionRequirement} is needed.
|
|
67
|
+
*
|
|
68
|
+
* - `'required'` — tracking cannot start, or an explicitly-enabled feature is dead, without it.
|
|
69
|
+
* - `'recommended'` — an active feature silently degrades without it; tracking still runs.
|
|
70
|
+
*/
|
|
71
|
+
export type PermissionImportance = 'required' | 'recommended';
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* One permission Beekon needs **for the current configuration**, each marked
|
|
75
|
+
* satisfied against the live grant — returned by `Beekon.getRequiredPermissions()`.
|
|
76
|
+
* Mirrors the native `PermissionRequirement`.
|
|
77
|
+
*
|
|
78
|
+
* Beekon never *requests* permission — the app owns that. This is the
|
|
79
|
+
* config-aware "doctor" companion to {@link PermissionStatus}: it reports
|
|
80
|
+
* activity-recognition (and, on Android, notifications) too.
|
|
81
|
+
*/
|
|
82
|
+
export type PermissionRequirement = {
|
|
83
|
+
/** The normalized permission. */
|
|
84
|
+
permission: BeekonPermission;
|
|
85
|
+
/** Whether tracking/a feature breaks (`'required'`) or merely degrades (`'recommended'`) when absent. */
|
|
86
|
+
importance: PermissionImportance;
|
|
87
|
+
/** Whether the live OS grant covers it right now. */
|
|
88
|
+
satisfied: boolean;
|
|
89
|
+
/** Human-readable explanation of why Beekon needs it / what degrades without it. */
|
|
90
|
+
rationale: string;
|
|
91
|
+
};
|