expo-beacon 0.7.23 → 0.7.25
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/android/src/main/java/expo/modules/beacon/BeaconConstants.kt +11 -14
- package/android/src/main/java/expo/modules/beacon/BeaconEventPlugin.kt +2 -0
- package/android/src/main/java/expo/modules/beacon/BeaconForegroundService.kt +16 -11
- package/android/src/main/java/expo/modules/beacon/BeaconPluginRegistry.kt +19 -0
- package/android/src/main/java/expo/modules/beacon/ExpoBeaconModule.kt +10 -0
- package/build/ExpoBeacon.types.d.ts +9 -0
- package/build/ExpoBeacon.types.d.ts.map +1 -1
- package/build/ExpoBeacon.types.js.map +1 -1
- package/ios/BeaconLifecycleDelegate.swift +8 -0
- package/ios/ExpoBeaconModule.swift +80 -19
- package/package.json +1 -1
- package/plugin/build/withBeaconAndroid.d.ts.map +1 -1
- package/plugin/build/withBeaconAndroid.js +4 -0
- package/plugin/build/withBeaconIOS.d.ts.map +1 -1
- package/plugin/build/withBeaconIOS.js +6 -0
- package/src/ExpoBeacon.types.ts +9 -0
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
package expo.modules.beacon
|
|
2
2
|
|
|
3
3
|
// Shared constants used across ExpoBeaconModule and BeaconForegroundService.
|
|
4
|
-
// NOTE:
|
|
5
|
-
//
|
|
6
|
-
//
|
|
7
|
-
//
|
|
4
|
+
// NOTE: Scan timing deviates from iOS intentionally — Android requires a non-zero
|
|
5
|
+
// between-scan gap to prevent OS-level BLE throttling.
|
|
6
|
+
// ENTER_HYSTERESIS_COUNT and EXIT_HYSTERESIS_COUNT should stay in sync with
|
|
7
|
+
// ExpoBeaconModule.swift (iOS).
|
|
8
8
|
|
|
9
9
|
internal const val PREFS_NAME = "expo.beacon.paired"
|
|
10
10
|
internal const val PREFS_KEY = "paired_beacons"
|
|
@@ -42,22 +42,19 @@ internal const val REGION_EXIT_PERIOD_MS = 60000L
|
|
|
42
42
|
*/
|
|
43
43
|
internal const val RECENT_RANGING_SIGHTING_GRACE_MS = REGION_EXIT_PERIOD_MS
|
|
44
44
|
|
|
45
|
-
/**
|
|
46
|
-
* Number of consecutive ranging misses before emitting a distance-based exit event.
|
|
47
|
-
* With a ~2.1 s scan cycle (1100 ms scan + 1000 ms gap), 10 misses ≈ 21 s of
|
|
48
|
-
* silence before declaring exit — tolerant of brief BLE gaps while still
|
|
49
|
-
* responsive to actual departures.
|
|
50
|
-
*/
|
|
51
|
-
internal const val EXIT_MISS_THRESHOLD = 10
|
|
52
|
-
|
|
53
45
|
/**
|
|
54
46
|
* Milliseconds of no valid BLE readings before starting the timeout countdown.
|
|
55
47
|
* Acts as a safety net when ranging cycles stop entirely (e.g. Doze mode).
|
|
56
48
|
*/
|
|
57
49
|
internal const val DISTANCE_INACTIVITY_MS = 60_000L
|
|
58
50
|
|
|
59
|
-
/** Number of consecutive readings required to confirm a distance-based enter
|
|
60
|
-
internal const val
|
|
51
|
+
/** Number of consecutive in-range readings required to confirm a distance-based enter transition. */
|
|
52
|
+
internal const val ENTER_HYSTERESIS_COUNT = 1
|
|
53
|
+
/** Number of consecutive out-of-range readings required to confirm a distance-based exit transition. */
|
|
54
|
+
internal const val EXIT_HYSTERESIS_COUNT = 3
|
|
55
|
+
|
|
56
|
+
/** Default seconds of silence after last sighting before a disappearance-based exit fires. */
|
|
57
|
+
internal const val DEFAULT_EXIT_TIMEOUT_SECONDS = 300.0
|
|
61
58
|
|
|
62
59
|
/** Default minimum RSSI (dBm) below which beacon readings are discarded as unreliable. */
|
|
63
60
|
internal const val DEFAULT_MIN_RSSI = -85
|
|
@@ -10,8 +10,10 @@ interface BeaconEventPlugin {
|
|
|
10
10
|
// iBeacon
|
|
11
11
|
fun onBeaconEnter(identifier: String, uuid: String, major: Int, minor: Int, distance: Double)
|
|
12
12
|
fun onBeaconExit(identifier: String, uuid: String, major: Int, minor: Int, distance: Double)
|
|
13
|
+
fun onBeaconTimeout(identifier: String, uuid: String, major: Int, minor: Int, distance: Double)
|
|
13
14
|
|
|
14
15
|
// Eddystone
|
|
15
16
|
fun onEddystoneEnter(identifier: String, namespace: String, instance: String, distance: Double)
|
|
16
17
|
fun onEddystoneExit(identifier: String, namespace: String, instance: String, distance: Double)
|
|
18
|
+
fun onEddystoneTimeout(identifier: String, namespace: String, instance: String, distance: Double)
|
|
17
19
|
}
|
|
@@ -81,6 +81,8 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
81
81
|
private var apiForwarder: BeaconApiForwarder? = null
|
|
82
82
|
// Event level: "all" emits distance + enter/exit/timeout; "events" suppresses distance.
|
|
83
83
|
@Volatile private var eventLevel: String = "all"
|
|
84
|
+
// Seconds of silence after last valid sighting before a disappearance-based exit fires.
|
|
85
|
+
@Volatile private var exitTimeoutMs: Long = (DEFAULT_EXIT_TIMEOUT_SECONDS * 1000.0).toLong()
|
|
84
86
|
|
|
85
87
|
override fun onCreate() {
|
|
86
88
|
super.onCreate()
|
|
@@ -187,6 +189,7 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
187
189
|
exitDistance = optPrefs.getString("exit_distance", null)?.toDoubleOrNull()
|
|
188
190
|
minRssiThreshold = optPrefs.getInt("min_rssi", DEFAULT_MIN_RSSI)
|
|
189
191
|
eventLevel = optPrefs.getString("level", "all") ?: "all"
|
|
192
|
+
exitTimeoutMs = ((optPrefs.getString("exit_timeout_seconds", null)?.toDoubleOrNull() ?: DEFAULT_EXIT_TIMEOUT_SECONDS) * 1000.0).toLong()
|
|
190
193
|
|
|
191
194
|
beaconManager.addMonitorNotifier(monitorNotifier)
|
|
192
195
|
beaconManager.addRangeNotifier(rangeNotifier)
|
|
@@ -442,14 +445,16 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
442
445
|
// On Android 17+ (API 37) the BLE scan callbacks are more intermittent: valid
|
|
443
446
|
// readings are interspersed with occasional null cycles even when the beacon is
|
|
444
447
|
// nearby. Resetting direction counters on every null would prevent the hysteresis
|
|
445
|
-
// from ever accumulating to
|
|
448
|
+
// from ever accumulating to ENTER_HYSTERESIS_COUNT, breaking enter/exit entirely while
|
|
446
449
|
// still allowing distance events (which fire on each individual valid reading).
|
|
447
450
|
// Direction counters are reset by evaluateDistanceHysteresis when a valid reading
|
|
448
451
|
// contradicts the current direction (e.g., in-range reading resets exitCounters).
|
|
449
452
|
val count = (missCounters[region.uniqueId] ?: 0) + 1
|
|
450
453
|
missCounters[region.uniqueId] = count
|
|
451
454
|
|
|
452
|
-
|
|
455
|
+
val lastSeen = lastSeenAtMs[region.uniqueId]
|
|
456
|
+
val silentMs = if (lastSeen != null) SystemClock.elapsedRealtime() - lastSeen else Long.MAX_VALUE
|
|
457
|
+
if (enteredRegions.contains(region.uniqueId) && silentMs >= exitTimeoutMs) {
|
|
453
458
|
enteredRegions.remove(region.uniqueId)
|
|
454
459
|
missCounters[region.uniqueId] = 0
|
|
455
460
|
enterCounters[region.uniqueId] = 0
|
|
@@ -520,7 +525,7 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
520
525
|
}
|
|
521
526
|
val count = (enterCounters[regionId] ?: 0) + 1
|
|
522
527
|
enterCounters[regionId] = count
|
|
523
|
-
if (count >=
|
|
528
|
+
if (count >= ENTER_HYSTERESIS_COUNT) {
|
|
524
529
|
enterCounters[regionId] = 0
|
|
525
530
|
return HysteresisAction.ENTER
|
|
526
531
|
}
|
|
@@ -533,7 +538,7 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
533
538
|
exitCounters[regionId] = 0
|
|
534
539
|
val count = (enterCounters[regionId] ?: 0) + 1
|
|
535
540
|
enterCounters[regionId] = count
|
|
536
|
-
if (!enteredRegions.contains(regionId) && count >=
|
|
541
|
+
if (!enteredRegions.contains(regionId) && count >= ENTER_HYSTERESIS_COUNT) {
|
|
537
542
|
enterCounters[regionId] = 0
|
|
538
543
|
return HysteresisAction.ENTER
|
|
539
544
|
}
|
|
@@ -542,7 +547,7 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
542
547
|
enterCounters[regionId] = 0
|
|
543
548
|
val count = (exitCounters[regionId] ?: 0) + 1
|
|
544
549
|
exitCounters[regionId] = count
|
|
545
|
-
if (enteredRegions.contains(regionId) && count >=
|
|
550
|
+
if (enteredRegions.contains(regionId) && count >= EXIT_HYSTERESIS_COUNT) {
|
|
546
551
|
exitCounters[regionId] = 0
|
|
547
552
|
return HysteresisAction.EXIT
|
|
548
553
|
}
|
|
@@ -628,18 +633,18 @@ class BeaconForegroundService : Service(), BeaconConsumer {
|
|
|
628
633
|
// Forward all produced events to remote API
|
|
629
634
|
apiForwarder?.forwardEvent(params)
|
|
630
635
|
|
|
631
|
-
// Dispatch enter/exit to registered plugins (e.g. to start/stop BGLocation)
|
|
632
|
-
if (eventType == "enter" || eventType == "exit") {
|
|
636
|
+
// Dispatch enter/exit/timeout to registered plugins (e.g. to start/stop BGLocation)
|
|
637
|
+
if (eventType == "enter" || eventType == "exit" || eventType == "timeout") {
|
|
633
638
|
val identifier = region.uniqueId
|
|
634
639
|
val uuid = if (!isEddystone) id1Str else ""
|
|
635
640
|
val major = if (!isEddystone) region.id2?.toInt() ?: 0 else 0
|
|
636
641
|
val minor = if (!isEddystone) region.id3?.toInt() ?: 0 else 0
|
|
637
642
|
val namespace = if (isEddystone) id1Str.removePrefix("0x") else ""
|
|
638
643
|
val instance = if (isEddystone) region.id2?.toString()?.removePrefix("0x") ?: "" else ""
|
|
639
|
-
|
|
640
|
-
BeaconPluginRegistry.dispatchEnter(isEddystone, identifier, uuid, major, minor, namespace, instance, distance)
|
|
641
|
-
|
|
642
|
-
BeaconPluginRegistry.
|
|
644
|
+
when (eventType) {
|
|
645
|
+
"enter" -> BeaconPluginRegistry.dispatchEnter(isEddystone, identifier, uuid, major, minor, namespace, instance, distance)
|
|
646
|
+
"exit" -> BeaconPluginRegistry.dispatchExit(isEddystone, identifier, uuid, major, minor, namespace, instance, distance)
|
|
647
|
+
"timeout" -> BeaconPluginRegistry.dispatchTimeout(isEddystone, identifier, uuid, major, minor, namespace, instance, distance)
|
|
643
648
|
}
|
|
644
649
|
}
|
|
645
650
|
|
|
@@ -58,4 +58,23 @@ object BeaconPluginRegistry {
|
|
|
58
58
|
}
|
|
59
59
|
}
|
|
60
60
|
}
|
|
61
|
+
|
|
62
|
+
internal fun dispatchTimeout(
|
|
63
|
+
isEddystone: Boolean,
|
|
64
|
+
identifier: String,
|
|
65
|
+
uuid: String,
|
|
66
|
+
major: Int,
|
|
67
|
+
minor: Int,
|
|
68
|
+
namespace: String,
|
|
69
|
+
instance: String,
|
|
70
|
+
distance: Double,
|
|
71
|
+
) {
|
|
72
|
+
plugins.forEach { plugin ->
|
|
73
|
+
if (isEddystone) {
|
|
74
|
+
plugin.onEddystoneTimeout(identifier, namespace, instance, distance)
|
|
75
|
+
} else {
|
|
76
|
+
plugin.onBeaconTimeout(identifier, uuid, major, minor, distance)
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
}
|
|
61
80
|
}
|
|
@@ -290,6 +290,7 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
|
|
|
290
290
|
var exitDistance: Double? = null
|
|
291
291
|
var minRssi: Int? = null
|
|
292
292
|
var level: String = "all"
|
|
293
|
+
var exitTimeoutSeconds: Double? = null
|
|
293
294
|
when (options) {
|
|
294
295
|
is Double -> maxDistance = options
|
|
295
296
|
is Map<*, *> -> {
|
|
@@ -299,6 +300,7 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
|
|
|
299
300
|
exitDistance = (map["exitDistance"] as? Number)?.toDouble()
|
|
300
301
|
minRssi = (map["minRssi"] as? Number)?.toInt()
|
|
301
302
|
level = (map["level"] as? String) ?: "all"
|
|
303
|
+
exitTimeoutSeconds = (map["exitTimeoutSeconds"] as? Number)?.toDouble()
|
|
302
304
|
val notifications = map["notifications"]
|
|
303
305
|
if (notifications is Map<*, *>) {
|
|
304
306
|
@Suppress("UNCHECKED_CAST")
|
|
@@ -327,6 +329,11 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
|
|
|
327
329
|
sendEvent("onBeaconError", mapOf("identifier" to "", "code" to "INVALID_EXIT_DISTANCE", "message" to "exitDistance must be greater than or equal to maxDistance"))
|
|
328
330
|
return@AsyncFunction
|
|
329
331
|
}
|
|
332
|
+
if (exitTimeoutSeconds != null && (!exitTimeoutSeconds.isFinite() || exitTimeoutSeconds <= 0.0)) {
|
|
333
|
+
promise.reject("INVALID_EXIT_TIMEOUT", "exitTimeoutSeconds must be a finite number greater than 0", null)
|
|
334
|
+
sendEvent("onBeaconError", mapOf("identifier" to "", "code" to "INVALID_EXIT_TIMEOUT", "message" to "exitTimeoutSeconds must be a finite number greater than 0"))
|
|
335
|
+
return@AsyncFunction
|
|
336
|
+
}
|
|
330
337
|
ctx.getSharedPreferences(MONITORING_OPTIONS_PREFS, Context.MODE_PRIVATE)
|
|
331
338
|
.edit().apply {
|
|
332
339
|
if (maxDistance != null) putString("max_distance", maxDistance.toString())
|
|
@@ -336,6 +343,8 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
|
|
|
336
343
|
if (minRssi != null) putInt("min_rssi", minRssi)
|
|
337
344
|
else remove("min_rssi")
|
|
338
345
|
putString("level", level)
|
|
346
|
+
if (exitTimeoutSeconds != null) putString("exit_timeout_seconds", exitTimeoutSeconds.toString())
|
|
347
|
+
else remove("exit_timeout_seconds")
|
|
339
348
|
}.apply()
|
|
340
349
|
// Verify we have the permissions needed for background monitoring
|
|
341
350
|
val hasLocation = ContextCompat.checkSelfPermission(ctx, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED
|
|
@@ -495,6 +504,7 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
|
|
|
495
504
|
optPrefs.getString("exit_distance", null)?.toDoubleOrNull()?.let { put("exitDistance", it) }
|
|
496
505
|
if (optPrefs.contains("min_rssi")) put("minRssi", optPrefs.getInt("min_rssi", -85))
|
|
497
506
|
optPrefs.getString("level", null)?.let { put("level", it) }
|
|
507
|
+
optPrefs.getString("exit_timeout_seconds", null)?.toDoubleOrNull()?.let { put("exitTimeoutSeconds", it) }
|
|
498
508
|
val json = ctx.getSharedPreferences(NOTIFICATION_CONFIG_PREFS, Context.MODE_PRIVATE)
|
|
499
509
|
.getString("config", null)
|
|
500
510
|
if (json != null) {
|
|
@@ -121,6 +121,8 @@ export type MonitoringConfig = {
|
|
|
121
121
|
exitDistance?: number;
|
|
122
122
|
minRssi?: number;
|
|
123
123
|
level?: 'all' | 'events';
|
|
124
|
+
/** Seconds after last beacon sighting before an exit event fires. Default: 300. */
|
|
125
|
+
exitTimeoutSeconds?: number;
|
|
124
126
|
notifications?: NotificationConfig;
|
|
125
127
|
};
|
|
126
128
|
/** Current state snapshot for a paired monitored device. */
|
|
@@ -173,6 +175,13 @@ export type MonitoringOptions = {
|
|
|
173
175
|
* - `'events'`: enter + exit + timeout only (no distance events).
|
|
174
176
|
*/
|
|
175
177
|
level?: 'all' | 'events';
|
|
178
|
+
/**
|
|
179
|
+
* Seconds after last beacon sighting before an exit event fires when the beacon
|
|
180
|
+
* disappears without moving outside the exit distance threshold.
|
|
181
|
+
*
|
|
182
|
+
* Default: 300 (5 minutes). Minimum: 1.
|
|
183
|
+
*/
|
|
184
|
+
exitTimeoutSeconds?: number;
|
|
176
185
|
/** Notification configuration overrides to apply for this monitoring session. */
|
|
177
186
|
notifications?: NotificationConfig;
|
|
178
187
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoBeacon.types.d.ts","sourceRoot":"","sources":["../src/ExpoBeacon.types.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"ExpoBeacon.types.d.ts","sourceRoot":"","sources":["../src/ExpoBeacon.types.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ExpoBeacon.types.js","sourceRoot":"","sources":["../src/ExpoBeacon.types.ts"],"names":[],"mappings":"","sourcesContent":["/** Raw beacon discovered during a scan. */\r\nexport type BeaconScanResult = {\r\n uuid: string; // iBeacon proximity UUID (uppercase, formatted)\r\n major: number; // iBeacon major value (0–65535)\r\n minor: number; // iBeacon minor value (0–65535)\r\n rssi: number; // Signal strength in dBm (negative number)\r\n distance: number; // Estimated distance in meters\r\n txPower: number; // Calibrated TX power\r\n /** BLE advertising device name. May be undefined on iOS (CoreLocation does not expose it for iBeacon). */\r\n name?: string;\r\n};\r\n\r\n/**\r\n * A beacon that has been paired/registered for monitoring.\r\n *\r\n * Note: Paired beacon data is stored unencrypted in UserDefaults (iOS) /\r\n * SharedPreferences (Android) and may be included in device backups.\r\n */\r\nexport type PairedBeacon = {\r\n identifier: string; // User-defined label (e.g. \"lobby-door\")\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n /** BLE advertising device name, if provided at pairing time. */\r\n name?: string;\r\n /**\r\n * Timeout in seconds. When set, the module fires `onBeaconTimeout` once\r\n * after the beacon has been continuously in range for this duration.\r\n * The timer resets if the beacon exits and re-enters range.\r\n *\r\n * The timeout countdown also starts if no BLE readings are received\r\n * for 60 seconds (e.g. due to Doze mode or background throttling).\r\n */\r\n timeoutSeconds?: number;\r\n};\r\n\r\n/** Payload for enter/exit region events. */\r\nexport type BeaconRegionEvent = {\r\n identifier: string; // Matches PairedBeacon.identifier\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n event: \"enter\" | \"exit\";\r\n /** Measured distance in metres at the time of the event (–1 if unavailable). */\r\n distance: number;\r\n /** Signal strength in dBm at the time of the event (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for periodic distance update events during monitoring. */\r\nexport type BeaconDistanceEvent = {\r\n identifier: string;\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n distance: number;\r\n /** Signal strength in dBm (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for beacon timeout events (beacon in range for configured duration). */\r\nexport type BeaconTimeoutEvent = {\r\n identifier: string;\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n /** Current distance in metres at the time the timeout fired. */\r\n distance: number;\r\n};\r\n\r\n/** Configuration for beacon enter/exit event notifications. */\r\nexport type BeaconNotificationConfig = {\r\n /** Whether to show enter/exit notifications. Default: true. */\r\n enabled?: boolean;\r\n /** Notification title on beacon enter. Default: \"Beacon Entered\". */\r\n enterTitle?: string;\r\n /** Notification title on beacon exit. Default: \"Beacon Exited\". */\r\n exitTitle?: string;\r\n /** Notification title on beacon timeout. Default: \"Beacon Timeout\". */\r\n timeoutTitle?: string;\r\n /**\r\n * Notification body template. Supports {identifier} and {event} placeholders.\r\n * Default: \"{identifier} region {event}ed\".\r\n */\r\n body?: string;\r\n /** Play a sound with the notification (iOS only). Default: true. */\r\n sound?: boolean;\r\n /** Android drawable resource name for the notification icon (e.g. \"ic_notification\"). */\r\n icon?: string;\r\n};\r\n\r\n/** Configuration for the Android foreground service notification (persistent status bar entry). */\r\nexport type ForegroundServiceConfig = {\r\n /** Title of the persistent notification. Default: \"Beacon Monitoring Active\". */\r\n title?: string;\r\n /** Body text of the persistent notification. Default: \"Monitoring for iBeacons in the background\". */\r\n text?: string;\r\n /** Android drawable resource name for the notification icon. */\r\n icon?: string;\r\n};\r\n\r\n/** Configuration for the Android notification channel. */\r\nexport type NotificationChannelConfig = {\r\n /** Channel display name shown in system settings. Default: \"Beacon Monitoring\". */\r\n name?: string;\r\n /** Channel description shown in system settings. Default: \"Used for background iBeacon region monitoring\". */\r\n description?: string;\r\n /**\r\n * Channel importance level. Default: 'low'.\r\n * Note: Android may ignore decreases in importance after first channel creation until the app is reinstalled.\r\n */\r\n importance?: \"low\" | \"default\" | \"high\";\r\n};\r\n\r\n/** Combined notification configuration for all notification types. */\r\nexport type NotificationConfig = {\r\n /** Settings for beacon enter/exit event notifications. */\r\n beaconEvents?: BeaconNotificationConfig;\r\n /** Settings for the persistent foreground service notification (Android only). */\r\n foregroundService?: ForegroundServiceConfig;\r\n /** Settings for the Android notification channel (Android only). */\r\n channel?: NotificationChannelConfig;\r\n};\r\n\r\n/** Snapshot of the current monitoring configuration and active state. */\r\nexport type MonitoringConfig = {\r\n /** Whether background monitoring is currently active. */\r\n isMonitoring: boolean;\r\n maxDistance?: number;\r\n exitDistance?: number;\r\n minRssi?: number;\r\n level?: 'all' | 'events';\r\n notifications?: NotificationConfig;\r\n};\r\n\r\n/** Current state snapshot for a paired monitored device. */\r\nexport type MonitoredDeviceState =\r\n | {\r\n kind: \"ibeacon\";\r\n identifier: string;\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n state: \"entered\" | \"exited\";\r\n /** Current distance in metres, or null when exited or no live reading is available. */\r\n distance: number | null;\r\n }\r\n | {\r\n kind: \"eddystone\";\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n state: \"entered\" | \"exited\";\r\n /** Current distance in metres, or null when exited or no live reading is available. */\r\n distance: number | null;\r\n };\r\n\r\n/** Options accepted by startMonitoring(). */\r\nexport type MonitoringOptions = {\r\n /**\r\n * Maximum distance in metres for distance-based enter events.\r\n * Exit events are always emitted when the region is lost.\r\n */\r\n maxDistance?: number;\r\n /**\r\n * Distance in metres at which exit events fire (must be ≥ maxDistance).\r\n * Creates a hysteresis band between enter and exit thresholds to prevent\r\n * rapid toggling near the boundary.\r\n *\r\n * Default when omitted: `maxDistance + min(maxDistance × 0.5, 2.5)`.\r\n * Only used when `maxDistance` is set.\r\n */\r\n exitDistance?: number;\r\n /**\r\n * Minimum RSSI (dBm) for a beacon reading to be considered valid.\r\n * Readings below this threshold are discarded as unreliable, preventing\r\n * false detections from reflected or distant signals.\r\n *\r\n * Default: -85. Typical range: -100 (very permissive) to -70 (strict).\r\n */\r\n minRssi?: number;\r\n /**\r\n * Controls which event types are emitted, logged, and forwarded to the API.\r\n *\r\n * - `'all'` (default): distance + enter + exit + timeout events.\r\n * - `'events'`: enter + exit + timeout only (no distance events).\r\n */\r\n level?: 'all' | 'events';\r\n /** Notification configuration overrides to apply for this monitoring session. */\r\n notifications?: NotificationConfig;\r\n};\r\n\r\n/** Eddystone frame type. */\r\nexport type EddystoneFrameType = \"uid\" | \"url\";\r\n\r\n/** Raw Eddystone beacon discovered during a scan. */\r\nexport type EddystoneScanResult = {\r\n frameType: EddystoneFrameType;\r\n /** 10-byte namespace ID as hex string (20 chars). Present for UID frames. */\r\n namespace?: string;\r\n /** 6-byte instance ID as hex string (12 chars). Present for UID frames. */\r\n instance?: string;\r\n /** Decoded URL. Present for URL frames. */\r\n url?: string;\r\n rssi: number;\r\n distance: number;\r\n txPower: number;\r\n /** BLE advertising device name. */\r\n name?: string;\r\n};\r\n\r\n/**\r\n * An Eddystone-UID beacon that has been paired/registered for monitoring.\r\n *\r\n * Note: Paired beacon data is stored unencrypted in UserDefaults (iOS) /\r\n * SharedPreferences (Android) and may be included in device backups.\r\n */\r\nexport type PairedEddystone = {\r\n identifier: string;\r\n /** 10-byte namespace ID as hex string (20 chars). */\r\n namespace: string;\r\n /** 6-byte instance ID as hex string (12 chars). */\r\n instance: string;\r\n /** BLE advertising device name, if provided at pairing time. */\r\n name?: string;\r\n /**\r\n * Timeout in seconds. When set, the module fires `onEddystoneTimeout` once\r\n * after the beacon has been continuously in range for this duration.\r\n * The timer resets if the beacon exits and re-enters range.\r\n *\r\n * The timeout countdown also starts if no BLE readings are received\r\n * for 60 seconds (e.g. due to Doze mode or background throttling).\r\n */\r\n timeoutSeconds?: number;\r\n};\r\n\r\n/** Payload for Eddystone enter/exit region events. */\r\nexport type EddystoneRegionEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n event: \"enter\" | \"exit\";\r\n /** Measured distance in metres at the time of the event (–1 if unavailable). */\r\n distance: number;\r\n /** Signal strength in dBm at the time of the event (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for periodic Eddystone distance update events during monitoring. */\r\nexport type EddystoneDistanceEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n distance: number;\r\n /** Signal strength in dBm (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for Eddystone timeout events (beacon in range for configured duration). */\r\nexport type EddystoneTimeoutEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n /** Current distance in metres at the time the timeout fired. */\r\n distance: number;\r\n};\r\n\r\n/** Payload for native beacon error events (monitoring/ranging failures). */\r\nexport type BeaconErrorEvent = {\r\n /** Region or constraint identifier, empty string if unavailable. */\r\n identifier: string;\r\n /** Machine-readable error code (e.g. \"MONITORING_FAILED\", \"RANGING_FAILED\", \"SECURITY_EXCEPTION\"). */\r\n code: string;\r\n /** Human-readable error message from the native layer. */\r\n message: string;\r\n};\r\n\r\n/** Module event map. */\r\nexport type ExpoBeaconModuleEvents = {\r\n onBeaconEnter: (params: BeaconRegionEvent) => void;\r\n onBeaconExit: (params: BeaconRegionEvent) => void;\r\n onBeaconDistance: (params: BeaconDistanceEvent) => void;\r\n /** Fired once after a paired beacon has been continuously in range for its configured `timeoutSeconds`. */\r\n onBeaconTimeout: (params: BeaconTimeoutEvent) => void;\r\n /** Fired continuously during a live scan as each iBeacon is detected. */\r\n onBeaconFound: (params: BeaconScanResult) => void;\r\n /** Fired continuously during a live scan as each Eddystone beacon is detected. */\r\n onEddystoneFound: (params: EddystoneScanResult) => void;\r\n onEddystoneEnter: (params: EddystoneRegionEvent) => void;\r\n onEddystoneExit: (params: EddystoneRegionEvent) => void;\r\n onEddystoneDistance: (params: EddystoneDistanceEvent) => void;\r\n /** Fired once after a paired Eddystone has been continuously in range for its configured `timeoutSeconds`. */\r\n onEddystoneTimeout: (params: EddystoneTimeoutEvent) => void;\r\n /** Fired when a native monitoring or ranging failure occurs (logged to DB and forwarded to JS). */\r\n onBeaconError: (params: BeaconErrorEvent) => void;\r\n};\r\n\r\n/** Options for filtering event logs. */\r\nexport type EventLogQueryOptions = {\r\n /** Maximum number of log entries to return (default: 1000, max: 10000). */\r\n limit?: number;\r\n /** Filter by event type (e.g. \"onBeaconEnter\", \"onBeaconExit\"). */\r\n eventType?: string;\r\n /** Only return events with timestamp >= this value (ms since epoch). */\r\n sinceTimestamp?: number;\r\n};\r\n\r\n/** A single logged beacon event entry. */\r\nexport type EventLogEntry = {\r\n id: number;\r\n /** Timestamp in milliseconds since epoch. */\r\n timestamp: number;\r\n /** The event type that was logged (e.g. \"onBeaconEnter\"). */\r\n eventType: string;\r\n /** Beacon identifier, if available. */\r\n identifier?: string;\r\n /** The full event payload that was sent to JS. */\r\n data: Record<string, unknown>;\r\n};\r\n"]}
|
|
1
|
+
{"version":3,"file":"ExpoBeacon.types.js","sourceRoot":"","sources":["../src/ExpoBeacon.types.ts"],"names":[],"mappings":"","sourcesContent":["/** Raw beacon discovered during a scan. */\r\nexport type BeaconScanResult = {\r\n uuid: string; // iBeacon proximity UUID (uppercase, formatted)\r\n major: number; // iBeacon major value (0–65535)\r\n minor: number; // iBeacon minor value (0–65535)\r\n rssi: number; // Signal strength in dBm (negative number)\r\n distance: number; // Estimated distance in meters\r\n txPower: number; // Calibrated TX power\r\n /** BLE advertising device name. May be undefined on iOS (CoreLocation does not expose it for iBeacon). */\r\n name?: string;\r\n};\r\n\r\n/**\r\n * A beacon that has been paired/registered for monitoring.\r\n *\r\n * Note: Paired beacon data is stored unencrypted in UserDefaults (iOS) /\r\n * SharedPreferences (Android) and may be included in device backups.\r\n */\r\nexport type PairedBeacon = {\r\n identifier: string; // User-defined label (e.g. \"lobby-door\")\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n /** BLE advertising device name, if provided at pairing time. */\r\n name?: string;\r\n /**\r\n * Timeout in seconds. When set, the module fires `onBeaconTimeout` once\r\n * after the beacon has been continuously in range for this duration.\r\n * The timer resets if the beacon exits and re-enters range.\r\n *\r\n * The timeout countdown also starts if no BLE readings are received\r\n * for 60 seconds (e.g. due to Doze mode or background throttling).\r\n */\r\n timeoutSeconds?: number;\r\n};\r\n\r\n/** Payload for enter/exit region events. */\r\nexport type BeaconRegionEvent = {\r\n identifier: string; // Matches PairedBeacon.identifier\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n event: \"enter\" | \"exit\";\r\n /** Measured distance in metres at the time of the event (–1 if unavailable). */\r\n distance: number;\r\n /** Signal strength in dBm at the time of the event (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for periodic distance update events during monitoring. */\r\nexport type BeaconDistanceEvent = {\r\n identifier: string;\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n distance: number;\r\n /** Signal strength in dBm (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for beacon timeout events (beacon in range for configured duration). */\r\nexport type BeaconTimeoutEvent = {\r\n identifier: string;\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n /** Current distance in metres at the time the timeout fired. */\r\n distance: number;\r\n};\r\n\r\n/** Configuration for beacon enter/exit event notifications. */\r\nexport type BeaconNotificationConfig = {\r\n /** Whether to show enter/exit notifications. Default: true. */\r\n enabled?: boolean;\r\n /** Notification title on beacon enter. Default: \"Beacon Entered\". */\r\n enterTitle?: string;\r\n /** Notification title on beacon exit. Default: \"Beacon Exited\". */\r\n exitTitle?: string;\r\n /** Notification title on beacon timeout. Default: \"Beacon Timeout\". */\r\n timeoutTitle?: string;\r\n /**\r\n * Notification body template. Supports {identifier} and {event} placeholders.\r\n * Default: \"{identifier} region {event}ed\".\r\n */\r\n body?: string;\r\n /** Play a sound with the notification (iOS only). Default: true. */\r\n sound?: boolean;\r\n /** Android drawable resource name for the notification icon (e.g. \"ic_notification\"). */\r\n icon?: string;\r\n};\r\n\r\n/** Configuration for the Android foreground service notification (persistent status bar entry). */\r\nexport type ForegroundServiceConfig = {\r\n /** Title of the persistent notification. Default: \"Beacon Monitoring Active\". */\r\n title?: string;\r\n /** Body text of the persistent notification. Default: \"Monitoring for iBeacons in the background\". */\r\n text?: string;\r\n /** Android drawable resource name for the notification icon. */\r\n icon?: string;\r\n};\r\n\r\n/** Configuration for the Android notification channel. */\r\nexport type NotificationChannelConfig = {\r\n /** Channel display name shown in system settings. Default: \"Beacon Monitoring\". */\r\n name?: string;\r\n /** Channel description shown in system settings. Default: \"Used for background iBeacon region monitoring\". */\r\n description?: string;\r\n /**\r\n * Channel importance level. Default: 'low'.\r\n * Note: Android may ignore decreases in importance after first channel creation until the app is reinstalled.\r\n */\r\n importance?: \"low\" | \"default\" | \"high\";\r\n};\r\n\r\n/** Combined notification configuration for all notification types. */\r\nexport type NotificationConfig = {\r\n /** Settings for beacon enter/exit event notifications. */\r\n beaconEvents?: BeaconNotificationConfig;\r\n /** Settings for the persistent foreground service notification (Android only). */\r\n foregroundService?: ForegroundServiceConfig;\r\n /** Settings for the Android notification channel (Android only). */\r\n channel?: NotificationChannelConfig;\r\n};\r\n\r\n/** Snapshot of the current monitoring configuration and active state. */\r\nexport type MonitoringConfig = {\r\n /** Whether background monitoring is currently active. */\r\n isMonitoring: boolean;\r\n maxDistance?: number;\r\n exitDistance?: number;\r\n minRssi?: number;\r\n level?: 'all' | 'events';\r\n /** Seconds after last beacon sighting before an exit event fires. Default: 300. */\r\n exitTimeoutSeconds?: number;\r\n notifications?: NotificationConfig;\r\n};\r\n\r\n/** Current state snapshot for a paired monitored device. */\r\nexport type MonitoredDeviceState =\r\n | {\r\n kind: \"ibeacon\";\r\n identifier: string;\r\n uuid: string;\r\n major: number;\r\n minor: number;\r\n state: \"entered\" | \"exited\";\r\n /** Current distance in metres, or null when exited or no live reading is available. */\r\n distance: number | null;\r\n }\r\n | {\r\n kind: \"eddystone\";\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n state: \"entered\" | \"exited\";\r\n /** Current distance in metres, or null when exited or no live reading is available. */\r\n distance: number | null;\r\n };\r\n\r\n/** Options accepted by startMonitoring(). */\r\nexport type MonitoringOptions = {\r\n /**\r\n * Maximum distance in metres for distance-based enter events.\r\n * Exit events are always emitted when the region is lost.\r\n */\r\n maxDistance?: number;\r\n /**\r\n * Distance in metres at which exit events fire (must be ≥ maxDistance).\r\n * Creates a hysteresis band between enter and exit thresholds to prevent\r\n * rapid toggling near the boundary.\r\n *\r\n * Default when omitted: `maxDistance + min(maxDistance × 0.5, 2.5)`.\r\n * Only used when `maxDistance` is set.\r\n */\r\n exitDistance?: number;\r\n /**\r\n * Minimum RSSI (dBm) for a beacon reading to be considered valid.\r\n * Readings below this threshold are discarded as unreliable, preventing\r\n * false detections from reflected or distant signals.\r\n *\r\n * Default: -85. Typical range: -100 (very permissive) to -70 (strict).\r\n */\r\n minRssi?: number;\r\n /**\r\n * Controls which event types are emitted, logged, and forwarded to the API.\r\n *\r\n * - `'all'` (default): distance + enter + exit + timeout events.\r\n * - `'events'`: enter + exit + timeout only (no distance events).\r\n */\r\n level?: 'all' | 'events';\r\n /**\r\n * Seconds after last beacon sighting before an exit event fires when the beacon\r\n * disappears without moving outside the exit distance threshold.\r\n *\r\n * Default: 300 (5 minutes). Minimum: 1.\r\n */\r\n exitTimeoutSeconds?: number;\r\n /** Notification configuration overrides to apply for this monitoring session. */\r\n notifications?: NotificationConfig;\r\n};\r\n\r\n/** Eddystone frame type. */\r\nexport type EddystoneFrameType = \"uid\" | \"url\";\r\n\r\n/** Raw Eddystone beacon discovered during a scan. */\r\nexport type EddystoneScanResult = {\r\n frameType: EddystoneFrameType;\r\n /** 10-byte namespace ID as hex string (20 chars). Present for UID frames. */\r\n namespace?: string;\r\n /** 6-byte instance ID as hex string (12 chars). Present for UID frames. */\r\n instance?: string;\r\n /** Decoded URL. Present for URL frames. */\r\n url?: string;\r\n rssi: number;\r\n distance: number;\r\n txPower: number;\r\n /** BLE advertising device name. */\r\n name?: string;\r\n};\r\n\r\n/**\r\n * An Eddystone-UID beacon that has been paired/registered for monitoring.\r\n *\r\n * Note: Paired beacon data is stored unencrypted in UserDefaults (iOS) /\r\n * SharedPreferences (Android) and may be included in device backups.\r\n */\r\nexport type PairedEddystone = {\r\n identifier: string;\r\n /** 10-byte namespace ID as hex string (20 chars). */\r\n namespace: string;\r\n /** 6-byte instance ID as hex string (12 chars). */\r\n instance: string;\r\n /** BLE advertising device name, if provided at pairing time. */\r\n name?: string;\r\n /**\r\n * Timeout in seconds. When set, the module fires `onEddystoneTimeout` once\r\n * after the beacon has been continuously in range for this duration.\r\n * The timer resets if the beacon exits and re-enters range.\r\n *\r\n * The timeout countdown also starts if no BLE readings are received\r\n * for 60 seconds (e.g. due to Doze mode or background throttling).\r\n */\r\n timeoutSeconds?: number;\r\n};\r\n\r\n/** Payload for Eddystone enter/exit region events. */\r\nexport type EddystoneRegionEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n event: \"enter\" | \"exit\";\r\n /** Measured distance in metres at the time of the event (–1 if unavailable). */\r\n distance: number;\r\n /** Signal strength in dBm at the time of the event (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for periodic Eddystone distance update events during monitoring. */\r\nexport type EddystoneDistanceEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n distance: number;\r\n /** Signal strength in dBm (0 if unavailable). */\r\n rssi?: number;\r\n};\r\n\r\n/** Payload for Eddystone timeout events (beacon in range for configured duration). */\r\nexport type EddystoneTimeoutEvent = {\r\n identifier: string;\r\n namespace: string;\r\n instance: string;\r\n /** Current distance in metres at the time the timeout fired. */\r\n distance: number;\r\n};\r\n\r\n/** Payload for native beacon error events (monitoring/ranging failures). */\r\nexport type BeaconErrorEvent = {\r\n /** Region or constraint identifier, empty string if unavailable. */\r\n identifier: string;\r\n /** Machine-readable error code (e.g. \"MONITORING_FAILED\", \"RANGING_FAILED\", \"SECURITY_EXCEPTION\"). */\r\n code: string;\r\n /** Human-readable error message from the native layer. */\r\n message: string;\r\n};\r\n\r\n/** Module event map. */\r\nexport type ExpoBeaconModuleEvents = {\r\n onBeaconEnter: (params: BeaconRegionEvent) => void;\r\n onBeaconExit: (params: BeaconRegionEvent) => void;\r\n onBeaconDistance: (params: BeaconDistanceEvent) => void;\r\n /** Fired once after a paired beacon has been continuously in range for its configured `timeoutSeconds`. */\r\n onBeaconTimeout: (params: BeaconTimeoutEvent) => void;\r\n /** Fired continuously during a live scan as each iBeacon is detected. */\r\n onBeaconFound: (params: BeaconScanResult) => void;\r\n /** Fired continuously during a live scan as each Eddystone beacon is detected. */\r\n onEddystoneFound: (params: EddystoneScanResult) => void;\r\n onEddystoneEnter: (params: EddystoneRegionEvent) => void;\r\n onEddystoneExit: (params: EddystoneRegionEvent) => void;\r\n onEddystoneDistance: (params: EddystoneDistanceEvent) => void;\r\n /** Fired once after a paired Eddystone has been continuously in range for its configured `timeoutSeconds`. */\r\n onEddystoneTimeout: (params: EddystoneTimeoutEvent) => void;\r\n /** Fired when a native monitoring or ranging failure occurs (logged to DB and forwarded to JS). */\r\n onBeaconError: (params: BeaconErrorEvent) => void;\r\n};\r\n\r\n/** Options for filtering event logs. */\r\nexport type EventLogQueryOptions = {\r\n /** Maximum number of log entries to return (default: 1000, max: 10000). */\r\n limit?: number;\r\n /** Filter by event type (e.g. \"onBeaconEnter\", \"onBeaconExit\"). */\r\n eventType?: string;\r\n /** Only return events with timestamp >= this value (ms since epoch). */\r\n sinceTimestamp?: number;\r\n};\r\n\r\n/** A single logged beacon event entry. */\r\nexport type EventLogEntry = {\r\n id: number;\r\n /** Timestamp in milliseconds since epoch. */\r\n timestamp: number;\r\n /** The event type that was logged (e.g. \"onBeaconEnter\"). */\r\n eventType: string;\r\n /** Beacon identifier, if available. */\r\n identifier?: string;\r\n /** The full event payload that was sent to JS. */\r\n data: Record<string, unknown>;\r\n};\r\n"]}
|
|
@@ -9,10 +9,12 @@ public protocol BeaconLifecycleDelegate: AnyObject {
|
|
|
9
9
|
// MARK: iBeacon
|
|
10
10
|
func beaconDidEnter(identifier: String, uuid: String, major: Int, minor: Int, distance: Double)
|
|
11
11
|
func beaconDidExit(identifier: String, uuid: String, major: Int, minor: Int, distance: Double)
|
|
12
|
+
func beaconDidTimeout(identifier: String, uuid: String, major: Int, minor: Int, distance: Double)
|
|
12
13
|
|
|
13
14
|
// MARK: Eddystone
|
|
14
15
|
func eddystoneDidEnter(identifier: String, namespace: String, instance: String, distance: Double)
|
|
15
16
|
func eddystoneDidExit(identifier: String, namespace: String, instance: String, distance: Double)
|
|
17
|
+
func eddystoneDidTimeout(identifier: String, namespace: String, instance: String, distance: Double)
|
|
16
18
|
}
|
|
17
19
|
|
|
18
20
|
/// Thread-safe registry for [BeaconLifecycleDelegate] plugins.
|
|
@@ -46,6 +48,12 @@ public final class BeaconLifecycleRegistry {
|
|
|
46
48
|
internal func dispatchEddystoneExit(identifier: String, namespace: String, instance: String, distance: Double) {
|
|
47
49
|
snapshot().forEach { $0.eddystoneDidExit(identifier: identifier, namespace: namespace, instance: instance, distance: distance) }
|
|
48
50
|
}
|
|
51
|
+
internal func dispatchBeaconTimeout(identifier: String, uuid: String, major: Int, minor: Int, distance: Double) {
|
|
52
|
+
snapshot().forEach { $0.beaconDidTimeout(identifier: identifier, uuid: uuid, major: major, minor: minor, distance: distance) }
|
|
53
|
+
}
|
|
54
|
+
internal func dispatchEddystoneTimeout(identifier: String, namespace: String, instance: String, distance: Double) {
|
|
55
|
+
snapshot().forEach { $0.eddystoneDidTimeout(identifier: identifier, namespace: namespace, instance: instance, distance: distance) }
|
|
56
|
+
}
|
|
49
57
|
|
|
50
58
|
private func snapshot() -> [any BeaconLifecycleDelegate] {
|
|
51
59
|
lock.lock(); defer { lock.unlock() }
|
|
@@ -13,19 +13,19 @@ private let NOTIFICATION_CONFIG_KEY = "expo.beacon.notification_config"
|
|
|
13
13
|
private let EVENT_LOGGING_ENABLED_KEY = "expo.beacon.event_logging_enabled"
|
|
14
14
|
private let MIN_RSSI_KEY = "expo.beacon.min_rssi"
|
|
15
15
|
private let EVENT_LEVEL_KEY = "expo.beacon.event_level"
|
|
16
|
+
private let EXIT_TIMEOUT_SECONDS_KEY = "expo.beacon.exit_timeout_seconds"
|
|
16
17
|
|
|
17
18
|
/// Default minimum RSSI (dBm) below which beacon readings are discarded as unreliable.
|
|
18
19
|
private let DEFAULT_MIN_RSSI: Int = -85
|
|
20
|
+
/// Default seconds of silence after last beacon sighting before a disappearance-based exit fires.
|
|
21
|
+
private let DEFAULT_EXIT_TIMEOUT_SECONDS: TimeInterval = 300.0
|
|
19
22
|
|
|
20
|
-
/// Number of consecutive
|
|
21
|
-
/// With ~1 s CoreLocation ranging cycles (iBeacon) or ~2 s Eddystone monitoring ticks,
|
|
22
|
-
/// 20 misses ≈ 20–40 s of silence before declaring exit — tolerant of iOS background
|
|
23
|
-
/// BLE throttling while still responsive to actual departures.
|
|
24
|
-
/// NOTE: Android uses 10 with a ~2.1 s scan cycle (≈21 s effective).
|
|
25
|
-
private let EXIT_MISS_THRESHOLD = 20
|
|
26
|
-
/// Number of consecutive readings required to confirm a distance-based enter or exit transition.
|
|
23
|
+
/// Number of consecutive in-range readings required before an enter event is emitted.
|
|
27
24
|
/// IMPORTANT: Keep in sync with BeaconConstants.kt (Android).
|
|
28
|
-
private let
|
|
25
|
+
private let ENTER_HYSTERESIS_COUNT = 1
|
|
26
|
+
/// Number of consecutive out-of-range readings required before an exit event is emitted.
|
|
27
|
+
/// IMPORTANT: Keep in sync with BeaconConstants.kt (Android).
|
|
28
|
+
private let EXIT_HYSTERESIS_COUNT = 3
|
|
29
29
|
|
|
30
30
|
/// Eddystone monitoring timer interval in seconds.
|
|
31
31
|
private let EDDYSTONE_MONITORING_TICK_INTERVAL: TimeInterval = 2.0
|
|
@@ -67,8 +67,10 @@ public class ExpoBeaconModule: Module {
|
|
|
67
67
|
private var distanceRangingConstraints: [String: CLBeaconIdentityConstraint] = [:]
|
|
68
68
|
// Identifiers currently in "entered" state (used for distance-driven enter/exit)
|
|
69
69
|
private var enteredRegions: Set<String> = []
|
|
70
|
-
// Consecutive miss counter per identifier (for
|
|
70
|
+
// Consecutive miss counter per identifier (for tracking silence; exit now time-based)
|
|
71
71
|
private var missCounters: [String: Int] = [:]
|
|
72
|
+
// Per-identifier timestamp of the last valid ranging reading (for time-based exit detection)
|
|
73
|
+
private var lastSeenTimes: [String: Date] = [:]
|
|
72
74
|
// Hysteresis counters: consecutive readings inside/outside threshold per identifier
|
|
73
75
|
private var enterCounters: [String: Int] = [:]
|
|
74
76
|
private var exitCounters: [String: Int] = [:]
|
|
@@ -105,6 +107,9 @@ public class ExpoBeaconModule: Module {
|
|
|
105
107
|
/// Event level: "all" emits distance + enter/exit/timeout; "events" suppresses distance.
|
|
106
108
|
private var eventLevel: String = "all"
|
|
107
109
|
|
|
110
|
+
/// Seconds of silence after last valid beacon sighting before a miss-based exit fires.
|
|
111
|
+
private var exitTimeoutSeconds: TimeInterval = DEFAULT_EXIT_TIMEOUT_SECONDS
|
|
112
|
+
|
|
108
113
|
/// Distance smoothing (EMA) state per identifier.
|
|
109
114
|
private var smoothedDistances: [String: Double] = [:]
|
|
110
115
|
/// EMA weight for new readings. 0.4 balances responsiveness vs noise rejection.
|
|
@@ -342,12 +347,14 @@ public class ExpoBeaconModule: Module {
|
|
|
342
347
|
var maxDistance: Double? = nil
|
|
343
348
|
var exitDistance: Double? = nil
|
|
344
349
|
var minRssi: Int? = nil
|
|
350
|
+
var exitTimeoutSecs: Double? = nil
|
|
345
351
|
if let dist: Double = options?.get() {
|
|
346
352
|
maxDistance = dist
|
|
347
353
|
} else if let map: [String: Any] = options?.get() {
|
|
348
354
|
maxDistance = map["maxDistance"] as? Double
|
|
349
355
|
exitDistance = map["exitDistance"] as? Double
|
|
350
356
|
minRssi = map["minRssi"] as? Int
|
|
357
|
+
exitTimeoutSecs = map["exitTimeoutSeconds"] as? Double
|
|
351
358
|
if let lvl = map["level"] as? String, lvl == "events" || lvl == "all" {
|
|
352
359
|
self.eventLevel = lvl
|
|
353
360
|
self.defaults.set(lvl, forKey: EVENT_LEVEL_KEY)
|
|
@@ -381,6 +388,11 @@ public class ExpoBeaconModule: Module {
|
|
|
381
388
|
self.sendLoggedEvent("onBeaconError", ["identifier": "", "code": "INVALID_EXIT_DISTANCE", "message": "exitDistance must be greater than or equal to maxDistance"])
|
|
382
389
|
return
|
|
383
390
|
}
|
|
391
|
+
if let t = exitTimeoutSecs, (!t.isFinite || t <= 0) {
|
|
392
|
+
promise.reject("INVALID_EXIT_TIMEOUT", "exitTimeoutSeconds must be a finite number greater than 0")
|
|
393
|
+
self.sendLoggedEvent("onBeaconError", ["identifier": "", "code": "INVALID_EXIT_TIMEOUT", "message": "exitTimeoutSeconds must be a finite number greater than 0"])
|
|
394
|
+
return
|
|
395
|
+
}
|
|
384
396
|
if let dist = maxDistance {
|
|
385
397
|
self.defaults.set(dist, forKey: MAX_DISTANCE_KEY)
|
|
386
398
|
} else {
|
|
@@ -398,6 +410,13 @@ public class ExpoBeaconModule: Module {
|
|
|
398
410
|
self.defaults.removeObject(forKey: MIN_RSSI_KEY)
|
|
399
411
|
self.minRssiThreshold = DEFAULT_MIN_RSSI
|
|
400
412
|
}
|
|
413
|
+
if let t = exitTimeoutSecs {
|
|
414
|
+
self.defaults.set(t, forKey: EXIT_TIMEOUT_SECONDS_KEY)
|
|
415
|
+
self.exitTimeoutSeconds = t
|
|
416
|
+
} else {
|
|
417
|
+
self.defaults.removeObject(forKey: EXIT_TIMEOUT_SECONDS_KEY)
|
|
418
|
+
self.exitTimeoutSeconds = DEFAULT_EXIT_TIMEOUT_SECONDS
|
|
419
|
+
}
|
|
401
420
|
self.defaults.set(true, forKey: IS_MONITORING_KEY)
|
|
402
421
|
self.requestLocationPermission { granted in
|
|
403
422
|
guard granted else {
|
|
@@ -422,7 +441,10 @@ public class ExpoBeaconModule: Module {
|
|
|
422
441
|
self.defaults.removeObject(forKey: MAX_DISTANCE_KEY)
|
|
423
442
|
self.defaults.removeObject(forKey: EXIT_DISTANCE_KEY)
|
|
424
443
|
self.defaults.removeObject(forKey: EVENT_LEVEL_KEY)
|
|
444
|
+
self.defaults.removeObject(forKey: EXIT_TIMEOUT_SECONDS_KEY)
|
|
425
445
|
self.eventLevel = "all"
|
|
446
|
+
self.exitTimeoutSeconds = DEFAULT_EXIT_TIMEOUT_SECONDS
|
|
447
|
+
self.lastSeenTimes.removeAll()
|
|
426
448
|
self.stopRegionMonitoring()
|
|
427
449
|
promise.resolve(nil)
|
|
428
450
|
}
|
|
@@ -541,6 +563,9 @@ public class ExpoBeaconModule: Module {
|
|
|
541
563
|
if let level = self.defaults.string(forKey: EVENT_LEVEL_KEY) {
|
|
542
564
|
result["level"] = level
|
|
543
565
|
}
|
|
566
|
+
if let t = self.defaults.object(forKey: EXIT_TIMEOUT_SECONDS_KEY) as? Double {
|
|
567
|
+
result["exitTimeoutSeconds"] = t
|
|
568
|
+
}
|
|
544
569
|
if let json = self.defaults.string(forKey: NOTIFICATION_CONFIG_KEY),
|
|
545
570
|
let data = json.data(using: .utf8),
|
|
546
571
|
let obj = try? JSONSerialization.jsonObject(with: data) as? [String: Any] {
|
|
@@ -647,6 +672,13 @@ public class ExpoBeaconModule: Module {
|
|
|
647
672
|
// Restore persisted event level (survives app restarts)
|
|
648
673
|
eventLevel = defaults.string(forKey: EVENT_LEVEL_KEY) ?? "all"
|
|
649
674
|
|
|
675
|
+
// Restore persisted exit timeout (survives app restarts)
|
|
676
|
+
if let t = defaults.object(forKey: EXIT_TIMEOUT_SECONDS_KEY) as? Double, t > 0 {
|
|
677
|
+
exitTimeoutSeconds = t
|
|
678
|
+
} else {
|
|
679
|
+
exitTimeoutSeconds = DEFAULT_EXIT_TIMEOUT_SECONDS
|
|
680
|
+
}
|
|
681
|
+
|
|
650
682
|
let beacons = loadPairedBeaconsRaw()
|
|
651
683
|
|
|
652
684
|
// CLLocationManager supports a maximum of 20 monitored regions.
|
|
@@ -708,6 +740,7 @@ public class ExpoBeaconModule: Module {
|
|
|
708
740
|
distanceRangingConstraints.removeAll()
|
|
709
741
|
enteredRegions.removeAll()
|
|
710
742
|
missCounters.removeAll()
|
|
743
|
+
lastSeenTimes.removeAll()
|
|
711
744
|
enterCounters.removeAll()
|
|
712
745
|
exitCounters.removeAll()
|
|
713
746
|
smoothedDistances.removeAll()
|
|
@@ -1066,6 +1099,14 @@ public class ExpoBeaconModule: Module {
|
|
|
1066
1099
|
minor: params["minor"] as? Int ?? 0,
|
|
1067
1100
|
distance: distance
|
|
1068
1101
|
)
|
|
1102
|
+
case "onBeaconTimeout":
|
|
1103
|
+
r.dispatchBeaconTimeout(
|
|
1104
|
+
identifier: identifier,
|
|
1105
|
+
uuid: params["uuid"] as? String ?? "",
|
|
1106
|
+
major: params["major"] as? Int ?? 0,
|
|
1107
|
+
minor: params["minor"] as? Int ?? 0,
|
|
1108
|
+
distance: distance
|
|
1109
|
+
)
|
|
1069
1110
|
case "onEddystoneEnter":
|
|
1070
1111
|
r.dispatchEddystoneEnter(
|
|
1071
1112
|
identifier: identifier,
|
|
@@ -1080,6 +1121,13 @@ public class ExpoBeaconModule: Module {
|
|
|
1080
1121
|
instance: params["instance"] as? String ?? "",
|
|
1081
1122
|
distance: distance
|
|
1082
1123
|
)
|
|
1124
|
+
case "onEddystoneTimeout":
|
|
1125
|
+
r.dispatchEddystoneTimeout(
|
|
1126
|
+
identifier: identifier,
|
|
1127
|
+
namespace: params["namespace"] as? String ?? "",
|
|
1128
|
+
instance: params["instance"] as? String ?? "",
|
|
1129
|
+
distance: distance
|
|
1130
|
+
)
|
|
1083
1131
|
default:
|
|
1084
1132
|
break
|
|
1085
1133
|
}
|
|
@@ -1246,14 +1294,23 @@ public class ExpoBeaconModule: Module {
|
|
|
1246
1294
|
|
|
1247
1295
|
// Not seen recently — reset exit counter (miss counter handles exit
|
|
1248
1296
|
// separately) but preserve enter counter so that background BLE
|
|
1249
|
-
// throttling gaps don't force re-accumulating
|
|
1297
|
+
// throttling gaps don't force re-accumulating ENTER_HYSTERESIS_COUNT reads.
|
|
1250
1298
|
eddystoneExitCounters[identifier] = 0
|
|
1251
1299
|
guard eddystoneEnteredRegions.contains(identifier) else { continue }
|
|
1252
1300
|
|
|
1253
1301
|
let count = (eddystoneMissCounters[identifier] ?? 0) + 1
|
|
1254
1302
|
eddystoneMissCounters[identifier] = count
|
|
1255
1303
|
|
|
1256
|
-
|
|
1304
|
+
// Fire exit only after silence exceeds the configured exitTimeoutSeconds.
|
|
1305
|
+
// eddystoneLatestSeen already tracks Date of last sighting for this identifier.
|
|
1306
|
+
let silentLongEnough: Bool
|
|
1307
|
+
if let lastSeen = eddystoneLatestSeen[identifier] {
|
|
1308
|
+
silentLongEnough = now.timeIntervalSince(lastSeen) >= exitTimeoutSeconds
|
|
1309
|
+
} else {
|
|
1310
|
+
silentLongEnough = false
|
|
1311
|
+
}
|
|
1312
|
+
|
|
1313
|
+
if silentLongEnough {
|
|
1257
1314
|
eddystoneEnteredRegions.remove(identifier)
|
|
1258
1315
|
eddystoneMissCounters[identifier] = 0
|
|
1259
1316
|
eddystoneEnterCounters[identifier] = 0
|
|
@@ -1477,7 +1534,7 @@ public class ExpoBeaconModule: Module {
|
|
|
1477
1534
|
if distance <= maxDist {
|
|
1478
1535
|
exitCtrs[identifier] = 0
|
|
1479
1536
|
enterCtrs[identifier] = (enterCtrs[identifier] ?? 0) + 1
|
|
1480
|
-
if !entered.contains(identifier) && (enterCtrs[identifier] ?? 0) >=
|
|
1537
|
+
if !entered.contains(identifier) && (enterCtrs[identifier] ?? 0) >= ENTER_HYSTERESIS_COUNT {
|
|
1481
1538
|
entered.insert(identifier)
|
|
1482
1539
|
enterCtrs[identifier] = 0
|
|
1483
1540
|
return .enter
|
|
@@ -1485,7 +1542,7 @@ public class ExpoBeaconModule: Module {
|
|
|
1485
1542
|
} else if distance > exitDist {
|
|
1486
1543
|
enterCtrs[identifier] = 0
|
|
1487
1544
|
exitCtrs[identifier] = (exitCtrs[identifier] ?? 0) + 1
|
|
1488
|
-
if entered.contains(identifier) && (exitCtrs[identifier] ?? 0) >=
|
|
1545
|
+
if entered.contains(identifier) && (exitCtrs[identifier] ?? 0) >= EXIT_HYSTERESIS_COUNT {
|
|
1489
1546
|
entered.remove(identifier)
|
|
1490
1547
|
exitCtrs[identifier] = 0
|
|
1491
1548
|
return .exit
|
|
@@ -1497,7 +1554,7 @@ public class ExpoBeaconModule: Module {
|
|
|
1497
1554
|
}
|
|
1498
1555
|
} else {
|
|
1499
1556
|
enterCtrs[identifier] = (enterCtrs[identifier] ?? 0) + 1
|
|
1500
|
-
if !entered.contains(identifier) && (enterCtrs[identifier] ?? 0) >=
|
|
1557
|
+
if !entered.contains(identifier) && (enterCtrs[identifier] ?? 0) >= ENTER_HYSTERESIS_COUNT {
|
|
1501
1558
|
entered.insert(identifier)
|
|
1502
1559
|
enterCtrs[identifier] = 0
|
|
1503
1560
|
return .enter
|
|
@@ -1559,8 +1616,9 @@ public class ExpoBeaconModule: Module {
|
|
|
1559
1616
|
let validBeacon = beacons.first(where: { $0.accuracy >= 0 && $0.rssi >= minRssiThreshold })
|
|
1560
1617
|
|
|
1561
1618
|
if let beacon = validBeacon {
|
|
1562
|
-
// Got a valid reading — reset miss counter
|
|
1619
|
+
// Got a valid reading — reset miss counter and record sighting time
|
|
1563
1620
|
missCounters[identifier] = 0
|
|
1621
|
+
lastSeenTimes[identifier] = Date()
|
|
1564
1622
|
// Valid BLE reading — reset inactivity timer.
|
|
1565
1623
|
rescheduleBeaconInactivity(identifier: identifier, beacon: beacon)
|
|
1566
1624
|
|
|
@@ -1572,7 +1630,7 @@ public class ExpoBeaconModule: Module {
|
|
|
1572
1630
|
// Enter/exit synthesis with hysteresis — always applied.
|
|
1573
1631
|
// When maxDistance is set, distance thresholds control transitions.
|
|
1574
1632
|
// When maxDistance is nil, pure presence-based hysteresis is used
|
|
1575
|
-
// (
|
|
1633
|
+
// (ENTER_HYSTERESIS_COUNT consecutive readings to confirm enter).
|
|
1576
1634
|
let maxDist = self.defaults.object(forKey: MAX_DISTANCE_KEY) as? Double
|
|
1577
1635
|
let exitDist = self.defaults.object(forKey: EXIT_DISTANCE_KEY) as? Double
|
|
1578
1636
|
|
|
@@ -1611,16 +1669,19 @@ public class ExpoBeaconModule: Module {
|
|
|
1611
1669
|
} else {
|
|
1612
1670
|
// No valid beacon reading — beacon may have disappeared.
|
|
1613
1671
|
// Preserve enter counter so background accuracy=-1 gaps don't
|
|
1614
|
-
// force re-accumulating
|
|
1672
|
+
// force re-accumulating ENTER_HYSTERESIS_COUNT reads from scratch.
|
|
1615
1673
|
exitCounters[identifier] = 0
|
|
1616
1674
|
let count = (missCounters[identifier] ?? 0) + 1
|
|
1617
1675
|
missCounters[identifier] = count
|
|
1618
1676
|
|
|
1619
|
-
if enteredRegions.contains(identifier)
|
|
1677
|
+
if enteredRegions.contains(identifier),
|
|
1678
|
+
let lastSeen = lastSeenTimes[identifier],
|
|
1679
|
+
Date().timeIntervalSince(lastSeen) >= exitTimeoutSeconds {
|
|
1620
1680
|
enteredRegions.remove(identifier)
|
|
1621
1681
|
missCounters[identifier] = 0
|
|
1622
1682
|
enterCounters[identifier] = 0
|
|
1623
1683
|
exitCounters[identifier] = 0
|
|
1684
|
+
lastSeenTimes.removeValue(forKey: identifier)
|
|
1624
1685
|
smoothedDistances.removeValue(forKey: identifier)
|
|
1625
1686
|
|
|
1626
1687
|
// Look up region info for the exit event payload
|
|
@@ -1655,7 +1716,7 @@ public class ExpoBeaconModule: Module {
|
|
|
1655
1716
|
fileprivate func handleDidEnterRegion(_ region: CLRegion) {
|
|
1656
1717
|
// Region callbacks are suppressed — all enter/exit logic goes through
|
|
1657
1718
|
// ranging-based hysteresis in handleDidRange for consistent behaviour
|
|
1658
|
-
// with
|
|
1719
|
+
// with ENTER_HYSTERESIS_COUNT / EXIT_HYSTERESIS_COUNT, regardless of whether maxDistance is set.
|
|
1659
1720
|
}
|
|
1660
1721
|
|
|
1661
1722
|
fileprivate func handleDidExitRegion(_ region: CLRegion) {
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withBeaconAndroid.d.ts","sourceRoot":"","sources":["../src/withBeaconAndroid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAoB,MAAM,sBAAsB,CAAC;AAMtE,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,
|
|
1
|
+
{"version":3,"file":"withBeaconAndroid.d.ts","sourceRoot":"","sources":["../src/withBeaconAndroid.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAoB,MAAM,sBAAsB,CAAC;AAMtE,wBAAgB,sBAAsB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CA8BlE;AAqCD,QAAA,MAAM,iBAAiB,EAAE,YA0DxB,CAAC;AAEF,eAAe,iBAAiB,CAAC"}
|
|
@@ -25,10 +25,14 @@ class BeaconGeoPlugin(ctx: Context) : BeaconEventPlugin {
|
|
|
25
25
|
bgGeo.start(noOp)
|
|
26
26
|
override fun onBeaconExit(identifier: String, uuid: String, major: Int, minor: Int, distance: Double) =
|
|
27
27
|
bgGeo.stop(noOp)
|
|
28
|
+
override fun onBeaconTimeout(identifier: String, uuid: String, major: Int, minor: Int, distance: Double) =
|
|
29
|
+
bgGeo.stop(noOp)
|
|
28
30
|
override fun onEddystoneEnter(identifier: String, namespace: String, instance: String, distance: Double) =
|
|
29
31
|
bgGeo.start(noOp)
|
|
30
32
|
override fun onEddystoneExit(identifier: String, namespace: String, instance: String, distance: Double) =
|
|
31
33
|
bgGeo.stop(noOp)
|
|
34
|
+
override fun onEddystoneTimeout(identifier: String, namespace: String, instance: String, distance: Double) =
|
|
35
|
+
bgGeo.stop(noOp)
|
|
32
36
|
}
|
|
33
37
|
`;
|
|
34
38
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"withBeaconIOS.d.ts","sourceRoot":"","sources":["../src/withBeaconIOS.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAsC,MAAM,sBAAsB,CAAC;AAMxF,wBAAgB,iBAAiB,IAAI,MAAM,
|
|
1
|
+
{"version":3,"file":"withBeaconIOS.d.ts","sourceRoot":"","sources":["../src/withBeaconIOS.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAsC,MAAM,sBAAsB,CAAC;AAMxF,wBAAgB,iBAAiB,IAAI,MAAM,CA0B1C;AA+ED,QAAA,MAAM,aAAa,EAAE,YAmEpB,CAAC;AAEF,eAAe,aAAa,CAAC"}
|
|
@@ -17,12 +17,18 @@ final class BeaconGeoPlugin: BeaconLifecycleDelegate {
|
|
|
17
17
|
func beaconDidExit(identifier: String, uuid: String, major: Int, minor: Int, distance: Double) {
|
|
18
18
|
BackgroundGeolocation.sharedInstance().stop()
|
|
19
19
|
}
|
|
20
|
+
func beaconDidTimeout(identifier: String, uuid: String, major: Int, minor: Int, distance: Double) {
|
|
21
|
+
BackgroundGeolocation.sharedInstance().stop()
|
|
22
|
+
}
|
|
20
23
|
func eddystoneDidEnter(identifier: String, namespace: String, instance: String, distance: Double) {
|
|
21
24
|
BackgroundGeolocation.sharedInstance().start()
|
|
22
25
|
}
|
|
23
26
|
func eddystoneDidExit(identifier: String, namespace: String, instance: String, distance: Double) {
|
|
24
27
|
BackgroundGeolocation.sharedInstance().stop()
|
|
25
28
|
}
|
|
29
|
+
func eddystoneDidTimeout(identifier: String, namespace: String, instance: String, distance: Double) {
|
|
30
|
+
BackgroundGeolocation.sharedInstance().stop()
|
|
31
|
+
}
|
|
26
32
|
}
|
|
27
33
|
`;
|
|
28
34
|
}
|
package/src/ExpoBeacon.types.ts
CHANGED
|
@@ -130,6 +130,8 @@ export type MonitoringConfig = {
|
|
|
130
130
|
exitDistance?: number;
|
|
131
131
|
minRssi?: number;
|
|
132
132
|
level?: 'all' | 'events';
|
|
133
|
+
/** Seconds after last beacon sighting before an exit event fires. Default: 300. */
|
|
134
|
+
exitTimeoutSeconds?: number;
|
|
133
135
|
notifications?: NotificationConfig;
|
|
134
136
|
};
|
|
135
137
|
|
|
@@ -186,6 +188,13 @@ export type MonitoringOptions = {
|
|
|
186
188
|
* - `'events'`: enter + exit + timeout only (no distance events).
|
|
187
189
|
*/
|
|
188
190
|
level?: 'all' | 'events';
|
|
191
|
+
/**
|
|
192
|
+
* Seconds after last beacon sighting before an exit event fires when the beacon
|
|
193
|
+
* disappears without moving outside the exit distance threshold.
|
|
194
|
+
*
|
|
195
|
+
* Default: 300 (5 minutes). Minimum: 1.
|
|
196
|
+
*/
|
|
197
|
+
exitTimeoutSeconds?: number;
|
|
189
198
|
/** Notification configuration overrides to apply for this monitoring session. */
|
|
190
199
|
notifications?: NotificationConfig;
|
|
191
200
|
};
|