expo-beacon 0.3.2 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -21,6 +21,8 @@ import org.json.JSONObject
21
21
 
22
22
  private const val PREFS_NAME = "expo.beacon.paired"
23
23
  private const val PREFS_KEY = "paired_beacons"
24
+ private const val EDDYSTONE_PREFS_NAME = "expo.beacon.paired_eddystones"
25
+ private const val EDDYSTONE_PREFS_KEY = "paired_eddystones"
24
26
  private const val NOTIFICATION_CONFIG_PREFS = "expo.beacon.notification_config"
25
27
 
26
28
  class ExpoBeaconModule : Module(), BeaconConsumer {
@@ -35,6 +37,18 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
35
37
  BeaconParser().setBeaconLayout("m:2-3=0215,i:4-19,i:20-21,i:22-23,p:24-24,d:25-25")
36
38
  )
37
39
  }
40
+ // Register Eddystone-UID parser
41
+ if (manager.beaconParsers.none { it.layout?.contains("s:0-1=feaa,m:2-2=00") == true }) {
42
+ manager.beaconParsers.add(
43
+ BeaconParser().setBeaconLayout("s:0-1=feaa,m:2-2=00,p:3-3:-41,i:4-13,i:14-19")
44
+ )
45
+ }
46
+ // Register Eddystone-URL parser
47
+ if (manager.beaconParsers.none { it.layout?.contains("s:0-1=feaa,m:2-2=10") == true }) {
48
+ manager.beaconParsers.add(
49
+ BeaconParser().setBeaconLayout("s:0-1=feaa,m:2-2=10,p:3-3:-41,i:4-20v")
50
+ )
51
+ }
38
52
  }
39
53
  }
40
54
 
@@ -42,6 +56,10 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
42
56
  appContext.reactContext!!.getSharedPreferences(PREFS_NAME, Context.MODE_PRIVATE)
43
57
  }
44
58
 
59
+ private val eddystonePrefs: SharedPreferences by lazy {
60
+ appContext.reactContext!!.getSharedPreferences(EDDYSTONE_PREFS_NAME, Context.MODE_PRIVATE)
61
+ }
62
+
45
63
  // Coroutine scope tied to module lifecycle
46
64
  private val moduleScope = CoroutineScope(Dispatchers.Main + SupervisorJob())
47
65
 
@@ -50,6 +68,7 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
50
68
 
51
69
  // Current one-shot scan state
52
70
  private var scanPromise: Promise? = null
71
+ private var eddystoneScanPromise: Promise? = null
53
72
  private var scanJob: Job? = null
54
73
  private val scanResults = mutableListOf<Beacon>()
55
74
  private var scanUuidFilter: Set<String> = emptySet()
@@ -62,10 +81,10 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
62
81
  override fun definition() = ModuleDefinition {
63
82
  Name("ExpoBeacon")
64
83
 
65
- Events("onBeaconEnter", "onBeaconExit", "onBeaconDistance", "onBeaconFound")
84
+ Events("onBeaconEnter", "onBeaconExit", "onBeaconDistance", "onBeaconFound", "onEddystoneFound", "onEddystoneEnter", "onEddystoneExit", "onEddystoneDistance")
66
85
 
67
86
  AsyncFunction("scanForBeaconsAsync") { uuids: List<String>?, scanDurationMs: Int, promise: Promise ->
68
- if (scanPromise != null) {
87
+ if (scanPromise != null || eddystoneScanPromise != null) {
69
88
  promise.reject("SCAN_IN_PROGRESS", "A scan is already running", null)
70
89
  return@AsyncFunction
71
90
  }
@@ -114,6 +133,29 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
114
133
  null
115
134
  }
116
135
 
136
+ AsyncFunction("scanForEddystonesAsync") { scanDurationMs: Int, promise: Promise ->
137
+ if (scanPromise != null || eddystoneScanPromise != null) {
138
+ promise.reject("SCAN_IN_PROGRESS", "A scan is already running", null)
139
+ return@AsyncFunction
140
+ }
141
+ scanResults.clear()
142
+ eddystoneScanPromise = promise
143
+
144
+ beaconManager.addRangeNotifier(scanRangeNotifier)
145
+
146
+ if (!isBoundForScan) {
147
+ isBoundForScan = true
148
+ beaconManager.bind(this@ExpoBeaconModule)
149
+ } else {
150
+ startScanRanging()
151
+ }
152
+
153
+ scanJob = moduleScope.launch {
154
+ delay(scanDurationMs.toLong())
155
+ stopEddystoneScanAndResolve()
156
+ }
157
+ }
158
+
117
159
  Function("pairBeacon") { identifier: String, uuid: String, major: Int, minor: Int ->
118
160
  // Validate UUID format
119
161
  try {
@@ -169,6 +211,45 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
169
211
  }
170
212
  }
171
213
 
214
+ Function("pairEddystone") { identifier: String, namespace: String, instance: String ->
215
+ val eddystones = loadPairedEddystonesJson()
216
+ val filtered = (0 until eddystones.length())
217
+ .map { eddystones.getJSONObject(it) }
218
+ .filter { it.getString("identifier") != identifier }
219
+
220
+ val arr = JSONArray()
221
+ filtered.forEach { arr.put(it) }
222
+ val newEddystone = JSONObject().apply {
223
+ put("identifier", identifier)
224
+ put("namespace", namespace)
225
+ put("instance", instance)
226
+ }
227
+ arr.put(newEddystone)
228
+ eddystonePrefs.edit().putString(EDDYSTONE_PREFS_KEY, arr.toString()).apply()
229
+ }
230
+
231
+ Function("unpairEddystone") { identifier: String ->
232
+ val eddystones = loadPairedEddystonesJson()
233
+ val filtered = (0 until eddystones.length())
234
+ .map { eddystones.getJSONObject(it) }
235
+ .filter { it.getString("identifier") != identifier }
236
+ val arr = JSONArray()
237
+ filtered.forEach { arr.put(it) }
238
+ eddystonePrefs.edit().putString(EDDYSTONE_PREFS_KEY, arr.toString()).apply()
239
+ }
240
+
241
+ Function("getPairedEddystones") {
242
+ val eddystones = loadPairedEddystonesJson()
243
+ (0 until eddystones.length()).map { i ->
244
+ val e = eddystones.getJSONObject(i)
245
+ mapOf(
246
+ "identifier" to e.getString("identifier"),
247
+ "namespace" to e.getString("namespace"),
248
+ "instance" to e.getString("instance")
249
+ )
250
+ }
251
+ }
252
+
172
253
  AsyncFunction("startMonitoring") { options: Any?, promise: Promise ->
173
254
  val ctx = appContext.reactContext!!
174
255
  var maxDistance: Double? = null
@@ -268,6 +349,8 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
268
349
  OnDestroy {
269
350
  this@ExpoBeaconModule.unregisterEventReceiver()
270
351
  this@ExpoBeaconModule.scanJob?.cancel()
352
+ this@ExpoBeaconModule.scanPromise = null
353
+ this@ExpoBeaconModule.eddystoneScanPromise = null
271
354
  this@ExpoBeaconModule.moduleScope.cancel()
272
355
  if (this@ExpoBeaconModule.continuousScanActive) {
273
356
  this@ExpoBeaconModule.continuousScanActive = false
@@ -284,7 +367,7 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
284
367
  // --- BeaconConsumer (for scan binding) ---
285
368
 
286
369
  override fun onBeaconServiceConnect() {
287
- if (scanPromise != null) startScanRanging()
370
+ if (scanPromise != null || eddystoneScanPromise != null) startScanRanging()
288
371
  if (continuousScanActive) startContinuousRanging()
289
372
  }
290
373
 
@@ -315,14 +398,18 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
315
398
 
316
399
  private val continuousScanRangeNotifier = RangeNotifier { beacons, _ ->
317
400
  beacons.forEach { beacon ->
318
- sendEvent("onBeaconFound", mapOf(
319
- "uuid" to beacon.id1.toString().uppercase(),
320
- "major" to beacon.id2.toInt(),
321
- "minor" to beacon.id3.toInt(),
322
- "rssi" to beacon.rssi,
323
- "distance" to beacon.distance,
324
- "txPower" to beacon.txPower
325
- ))
401
+ if (beacon.serviceUuid == 0xfeaa) {
402
+ sendEvent("onEddystoneFound", eddystoneBeaconToMap(beacon))
403
+ } else {
404
+ sendEvent("onBeaconFound", mapOf(
405
+ "uuid" to beacon.id1.toString().uppercase(),
406
+ "major" to beacon.id2.toInt(),
407
+ "minor" to beacon.id3.toInt(),
408
+ "rssi" to beacon.rssi,
409
+ "distance" to beacon.distance,
410
+ "txPower" to beacon.txPower
411
+ ))
412
+ }
326
413
  }
327
414
  }
328
415
 
@@ -341,7 +428,7 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
341
428
  } catch (_: RemoteException) {}
342
429
  beaconManager.removeRangeNotifier(scanRangeNotifier)
343
430
 
344
- val results = scanResults.distinctBy { "${it.id1}:${it.id2}:${it.id3}" }.map { beacon ->
431
+ val results = scanResults.filter { it.serviceUuid != 0xfeaa }.distinctBy { "${it.id1}:${it.id2}:${it.id3}" }.map { beacon ->
345
432
  mapOf(
346
433
  "uuid" to beacon.id1.toString().uppercase(),
347
434
  "major" to beacon.id2.toInt(),
@@ -356,6 +443,74 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
356
443
  scanUuidFilter = emptySet()
357
444
  }
358
445
 
446
+ private fun stopEddystoneScanAndResolve() {
447
+ scanJob?.cancel()
448
+ try {
449
+ beaconManager.stopRangingBeaconsInRegion(Region("scanRegion", null, null, null))
450
+ } catch (_: RemoteException) {}
451
+ beaconManager.removeRangeNotifier(scanRangeNotifier)
452
+
453
+ val results = scanResults
454
+ .filter { it.serviceUuid == 0xfeaa }
455
+ .distinctBy {
456
+ if (it.identifiers.size >= 2) "uid:${it.id1}:${it.id2}"
457
+ else "url:${it.id1}"
458
+ }
459
+ .map { eddystoneBeaconToMap(it) }
460
+
461
+ eddystoneScanPromise?.resolve(results)
462
+ eddystoneScanPromise = null
463
+ scanResults.clear()
464
+ }
465
+
466
+ private fun eddystoneBeaconToMap(beacon: Beacon): Map<String, Any> {
467
+ val map = mutableMapOf<String, Any>(
468
+ "rssi" to beacon.rssi,
469
+ "distance" to beacon.distance,
470
+ "txPower" to beacon.txPower
471
+ )
472
+ if (beacon.identifiers.size >= 2) {
473
+ map["frameType"] = "uid"
474
+ map["namespace"] = beacon.id1.toString().removePrefix("0x")
475
+ map["instance"] = beacon.id2.toString().removePrefix("0x")
476
+ } else {
477
+ map["frameType"] = "url"
478
+ map["url"] = decodeEddystoneUrl(beacon.id1.toByteArray())
479
+ }
480
+ return map
481
+ }
482
+
483
+ private fun decodeEddystoneUrl(bytes: ByteArray): String {
484
+ if (bytes.isEmpty()) return ""
485
+ val schemes = arrayOf("http://www.", "https://www.", "http://", "https://")
486
+ val suffixes = mapOf(
487
+ 0x00.toByte() to ".com/", 0x01.toByte() to ".org/",
488
+ 0x02.toByte() to ".edu/", 0x03.toByte() to ".net/",
489
+ 0x04.toByte() to ".info/", 0x05.toByte() to ".biz/",
490
+ 0x06.toByte() to ".gov/",
491
+ 0x07.toByte() to ".com", 0x08.toByte() to ".org",
492
+ 0x09.toByte() to ".edu", 0x0A.toByte() to ".net",
493
+ 0x0B.toByte() to ".info", 0x0C.toByte() to ".biz",
494
+ 0x0D.toByte() to ".gov"
495
+ )
496
+ val schemeIndex = bytes[0].toInt() and 0xFF
497
+ if (schemeIndex >= schemes.size) return ""
498
+ val sb = StringBuilder(schemes[schemeIndex])
499
+ for (i in 1 until bytes.size) {
500
+ val b = bytes[i]
501
+ val suffix = suffixes[b]
502
+ if (suffix != null) {
503
+ sb.append(suffix)
504
+ } else {
505
+ val c = b.toInt() and 0xFF
506
+ if (c in 0x20..0x7E) {
507
+ sb.append(c.toChar())
508
+ }
509
+ }
510
+ }
511
+ return sb.toString()
512
+ }
513
+
359
514
  // --- Notification config helpers ---
360
515
 
361
516
  private fun mapToJson(map: Map<String, Any?>): JSONObject {
@@ -380,6 +535,11 @@ class ExpoBeaconModule : Module(), BeaconConsumer {
380
535
  return try { JSONArray(json) } catch (_: Exception) { JSONArray() }
381
536
  }
382
537
 
538
+ private fun loadPairedEddystonesJson(): JSONArray {
539
+ val json = eddystonePrefs.getString(EDDYSTONE_PREFS_KEY, "[]") ?: "[]"
540
+ return try { JSONArray(json) } catch (_: Exception) { JSONArray() }
541
+ }
542
+
383
543
  // --- Event receiver registration ---
384
544
 
385
545
  private fun registerEventReceiver() {
@@ -90,12 +90,56 @@ export type MonitoringOptions = {
90
90
  /** Notification configuration overrides to apply for this monitoring session. */
91
91
  notifications?: NotificationConfig;
92
92
  };
93
+ /** Eddystone frame type. */
94
+ export type EddystoneFrameType = "uid" | "url";
95
+ /** Raw Eddystone beacon discovered during a scan. */
96
+ export type EddystoneScanResult = {
97
+ frameType: EddystoneFrameType;
98
+ /** 10-byte namespace ID as hex string (20 chars). Present for UID frames. */
99
+ namespace?: string;
100
+ /** 6-byte instance ID as hex string (12 chars). Present for UID frames. */
101
+ instance?: string;
102
+ /** Decoded URL. Present for URL frames. */
103
+ url?: string;
104
+ rssi: number;
105
+ distance: number;
106
+ txPower: number;
107
+ };
108
+ /** An Eddystone-UID beacon that has been paired/registered for monitoring. */
109
+ export type PairedEddystone = {
110
+ identifier: string;
111
+ /** 10-byte namespace ID as hex string (20 chars). */
112
+ namespace: string;
113
+ /** 6-byte instance ID as hex string (12 chars). */
114
+ instance: string;
115
+ };
116
+ /** Payload for Eddystone enter/exit region events. */
117
+ export type EddystoneRegionEvent = {
118
+ identifier: string;
119
+ namespace: string;
120
+ instance: string;
121
+ event: "enter" | "exit";
122
+ /** Measured distance in metres at the time of the event (–1 if unavailable). */
123
+ distance: number;
124
+ };
125
+ /** Payload for periodic Eddystone distance update events during monitoring. */
126
+ export type EddystoneDistanceEvent = {
127
+ identifier: string;
128
+ namespace: string;
129
+ instance: string;
130
+ distance: number;
131
+ };
93
132
  /** Module event map. */
94
133
  export type ExpoBeaconModuleEvents = {
95
134
  onBeaconEnter: (params: BeaconRegionEvent) => void;
96
135
  onBeaconExit: (params: BeaconRegionEvent) => void;
97
136
  onBeaconDistance: (params: BeaconDistanceEvent) => void;
98
- /** Fired continuously during a live scan as each beacon is detected. */
137
+ /** Fired continuously during a live scan as each iBeacon is detected. */
99
138
  onBeaconFound: (params: BeaconScanResult) => void;
139
+ /** Fired continuously during a live scan as each Eddystone beacon is detected. */
140
+ onEddystoneFound: (params: EddystoneScanResult) => void;
141
+ onEddystoneEnter: (params: EddystoneRegionEvent) => void;
142
+ onEddystoneExit: (params: EddystoneRegionEvent) => void;
143
+ onEddystoneDistance: (params: EddystoneDistanceEvent) => void;
100
144
  };
101
145
  //# sourceMappingURL=ExpoBeacon.types.d.ts.map
@@ -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};\r\n\r\n/** A beacon that has been paired/registered for monitoring. */\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};\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};\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};\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 /**\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/** 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 /** Notification configuration overrides to apply for this monitoring session. */\r\n notifications?: NotificationConfig;\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 continuously during a live scan as each beacon is detected. */\r\n onBeaconFound: (params: BeaconScanResult) => void;\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};\r\n\r\n/** A beacon that has been paired/registered for monitoring. */\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};\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};\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};\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 /**\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/** 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 /** 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};\r\n\r\n/** An Eddystone-UID beacon that has been paired/registered for monitoring. */\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};\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};\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};\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 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};\r\n"]}
@@ -1,2 +1,76 @@
1
- export default module;
1
+ import { NativeModule } from "expo";
2
+ import { ExpoBeaconModuleEvents, BeaconScanResult, EddystoneScanResult, PairedBeacon, PairedEddystone, NotificationConfig, MonitoringOptions } from "./ExpoBeacon.types";
3
+ declare class ExpoBeaconModule extends NativeModule<ExpoBeaconModuleEvents> {
4
+ /**
5
+ * Start a one-shot iBeacon scan. Resolves with discovered beacons after scanDuration ms.
6
+ *
7
+ * Pass one or more UUIDs to scan for specific beacons (uses CoreLocation on iOS).
8
+ * Pass an empty array or omit to perform a wildcard scan that discovers all nearby
9
+ * iBeacons (uses CoreBluetooth on iOS — foreground only).
10
+ *
11
+ * @param uuids Proximity UUIDs to filter by. Empty/omitted = wildcard scan.
12
+ * @param scanDuration Duration in ms (default 5000)
13
+ */
14
+ scanForBeaconsAsync(uuids?: string[], scanDuration?: number): Promise<BeaconScanResult[]>;
15
+ /**
16
+ * Start a one-shot Eddystone beacon scan using BLE.
17
+ * Discovers Eddystone-UID and Eddystone-URL frames.
18
+ *
19
+ * @param scanDuration Duration in ms (default 5000)
20
+ */
21
+ scanForEddystonesAsync(scanDuration?: number): Promise<EddystoneScanResult[]>;
22
+ /**
23
+ * Register a beacon for persistent region monitoring.
24
+ */
25
+ pairBeacon(identifier: string, uuid: string, major: number, minor: number): void;
26
+ /**
27
+ * Remove a previously paired beacon.
28
+ */
29
+ unpairBeacon(identifier: string): void;
30
+ /**
31
+ * Return all currently paired beacons.
32
+ */
33
+ getPairedBeacons(): PairedBeacon[];
34
+ /**
35
+ * Register an Eddystone-UID beacon for persistent monitoring.
36
+ */
37
+ pairEddystone(identifier: string, namespace: string, instance: string): void;
38
+ /**
39
+ * Remove a previously paired Eddystone beacon.
40
+ */
41
+ unpairEddystone(identifier: string): void;
42
+ /**
43
+ * Return all currently paired Eddystone beacons.
44
+ */
45
+ getPairedEddystones(): PairedEddystone[];
46
+ /**
47
+ * Set persistent notification configuration. Settings are saved and applied to all
48
+ * subsequent monitoring sessions until explicitly changed.
49
+ */
50
+ setNotificationConfig(config: NotificationConfig): void;
51
+ /**
52
+ * Start background region monitoring for all paired beacons.
53
+ * On Android starts a foreground service.
54
+ * On iOS starts CLLocationManager region monitoring.
55
+ *
56
+ * Accepts a plain number (backward-compatible maxDistance shorthand) or a
57
+ * MonitoringOptions object with maxDistance and/or notification overrides.
58
+ */
59
+ startMonitoring(options?: MonitoringOptions | number): Promise<void>;
60
+ /**
61
+ * Stop background region monitoring.
62
+ */
63
+ stopMonitoring(): Promise<void>;
64
+ /**
65
+ * Start a continuous BLE scan. Fires `onBeaconFound` events as beacons are detected.
66
+ * Call stopContinuousScan() to end the scan.
67
+ */
68
+ startContinuousScan(): void;
69
+ /** Stop the continuous scan started by startContinuousScan(). */
70
+ stopContinuousScan(): void;
71
+ /** Request Bluetooth + Location permissions. Returns true if granted. */
72
+ requestPermissionsAsync(): Promise<boolean>;
73
+ }
74
+ declare const _default: ExpoBeaconModule;
75
+ export default _default;
2
76
  //# sourceMappingURL=ExpoBeaconModule.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoBeaconModule.d.ts","sourceRoot":"","sources":["../src/ExpoBeaconModule.ts"],"names":[],"mappings":"AA0FA,eAAe,MAAM,CAAC"}
1
+ {"version":3,"file":"ExpoBeaconModule.d.ts","sourceRoot":"","sources":["../src/ExpoBeaconModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAuB,MAAM,MAAM,CAAC;AAEzD,OAAO,EACL,sBAAsB,EACtB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,eAAe,EACf,kBAAkB,EAClB,iBAAiB,EAClB,MAAM,oBAAoB,CAAC;AAE5B,OAAO,OAAO,gBAAiB,SAAQ,YAAY,CAAC,sBAAsB,CAAC;IACzE;;;;;;;;;OASG;IACH,mBAAmB,CACjB,KAAK,CAAC,EAAE,MAAM,EAAE,EAChB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,gBAAgB,EAAE,CAAC;IAE9B;;;;;OAKG;IACH,sBAAsB,CACpB,YAAY,CAAC,EAAE,MAAM,GACpB,OAAO,CAAC,mBAAmB,EAAE,CAAC;IAEjC;;OAEG;IACH,UAAU,CACR,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,GACZ,IAAI;IAEP;;OAEG;IACH,YAAY,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAEtC;;OAEG;IACH,gBAAgB,IAAI,YAAY,EAAE;IAElC;;OAEG;IACH,aAAa,CACX,UAAU,EAAE,MAAM,EAClB,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,IAAI;IAEP;;OAEG;IACH,eAAe,CAAC,UAAU,EAAE,MAAM,GAAG,IAAI;IAEzC;;OAEG;IACH,mBAAmB,IAAI,eAAe,EAAE;IAExC;;;OAGG;IACH,qBAAqB,CAAC,MAAM,EAAE,kBAAkB,GAAG,IAAI;IAEvD;;;;;;;OAOG;IACH,eAAe,CAAC,OAAO,CAAC,EAAE,iBAAiB,GAAG,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAEpE;;OAEG;IACH,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC;IAE/B;;;OAGG;IACH,mBAAmB,IAAI,IAAI;IAE3B,iEAAiE;IACjE,kBAAkB,IAAI,IAAI;IAE1B,yEAAyE;IACzE,uBAAuB,IAAI,OAAO,CAAC,OAAO,CAAC;CAC5C;;AAED,wBAAmE"}
@@ -1,11 +1,3 @@
1
1
  import { requireNativeModule } from "expo";
2
- try {
3
- // eslint-disable-next-line import/no-mutable-exports
4
- var module = requireNativeModule("ExpoBeacon");
5
- }
6
- catch {
7
- throw new Error("expo-beacon: native module not found. Make sure you are using a development build " +
8
- "(not Expo Go) and have run `npx expo prebuild` followed by a native rebuild.");
9
- }
10
- export default module;
2
+ export default requireNativeModule("ExpoBeacon");
11
3
  //# sourceMappingURL=ExpoBeaconModule.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoBeaconModule.js","sourceRoot":"","sources":["../src/ExpoBeaconModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AAgFzD,IAAI,CAAC;IACH,qDAAqD;IACrD,IAAI,MAAM,GAAG,mBAAmB,CAAmB,YAAY,CAAC,CAAC;AACnE,CAAC;AAAC,MAAM,CAAC;IACP,MAAM,IAAI,KAAK,CACb,oFAAoF;QAClF,8EAA8E,CACjF,CAAC;AACJ,CAAC;AAED,eAAe,MAAM,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from \"expo\";\r\n\r\nimport {\r\n ExpoBeaconModuleEvents,\r\n BeaconScanResult,\r\n PairedBeacon,\r\n NotificationConfig,\r\n MonitoringOptions,\r\n} from \"./ExpoBeacon.types\";\r\n\r\ndeclare class ExpoBeaconModule extends NativeModule<ExpoBeaconModuleEvents> {\r\n /**\r\n * Start a one-shot iBeacon scan. Resolves with discovered beacons after scanDuration ms.\r\n *\r\n * Pass one or more UUIDs to scan for specific beacons (uses CoreLocation on iOS).\r\n * Pass an empty array or omit to perform a wildcard scan that discovers all nearby\r\n * iBeacons (uses CoreBluetooth on iOS — foreground only).\r\n *\r\n * @param uuids Proximity UUIDs to filter by. Empty/omitted = wildcard scan.\r\n * @param scanDuration Duration in ms (default 5000)\r\n */\r\n scanForBeaconsAsync(\r\n uuids?: string[],\r\n scanDuration?: number,\r\n ): Promise<BeaconScanResult[]>;\r\n\r\n /**\r\n * Register a beacon for persistent region monitoring.\r\n */\r\n pairBeacon(\r\n identifier: string,\r\n uuid: string,\r\n major: number,\r\n minor: number,\r\n ): void;\r\n\r\n /**\r\n * Remove a previously paired beacon.\r\n */\r\n unpairBeacon(identifier: string): void;\r\n\r\n /**\r\n * Return all currently paired beacons.\r\n */\r\n getPairedBeacons(): PairedBeacon[];\r\n\r\n /**\r\n * Set persistent notification configuration. Settings are saved and applied to all\r\n * subsequent monitoring sessions until explicitly changed.\r\n */\r\n setNotificationConfig(config: NotificationConfig): void;\r\n\r\n /**\r\n * Start background region monitoring for all paired beacons.\r\n * On Android starts a foreground service.\r\n * On iOS starts CLLocationManager region monitoring.\r\n *\r\n * Accepts a plain number (backward-compatible maxDistance shorthand) or a\r\n * MonitoringOptions object with maxDistance and/or notification overrides.\r\n */\r\n startMonitoring(options?: MonitoringOptions | number): Promise<void>;\r\n\r\n /**\r\n * Stop background region monitoring.\r\n */\r\n stopMonitoring(): Promise<void>;\r\n\r\n /**\r\n * Start a continuous BLE scan. Fires `onBeaconFound` events as beacons are detected.\r\n * Call stopContinuousScan() to end the scan.\r\n */\r\n startContinuousScan(): void;\r\n\r\n /** Stop the continuous scan started by startContinuousScan(). */\r\n stopContinuousScan(): void;\r\n\r\n /** Request Bluetooth + Location permissions. Returns true if granted. */\r\n requestPermissionsAsync(): Promise<boolean>;\r\n}\r\n\r\ntry {\r\n // eslint-disable-next-line import/no-mutable-exports\r\n var module = requireNativeModule<ExpoBeaconModule>(\"ExpoBeacon\");\r\n} catch {\r\n throw new Error(\r\n \"expo-beacon: native module not found. Make sure you are using a development build \" +\r\n \"(not Expo Go) and have run `npx expo prebuild` followed by a native rebuild.\",\r\n );\r\n}\r\n\r\nexport default module;\r\n"]}
1
+ {"version":3,"file":"ExpoBeaconModule.js","sourceRoot":"","sources":["../src/ExpoBeaconModule.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,mBAAmB,EAAE,MAAM,MAAM,CAAC;AA+GzD,eAAe,mBAAmB,CAAmB,YAAY,CAAC,CAAC","sourcesContent":["import { NativeModule, requireNativeModule } from \"expo\";\r\n\r\nimport {\r\n ExpoBeaconModuleEvents,\r\n BeaconScanResult,\r\n EddystoneScanResult,\r\n PairedBeacon,\r\n PairedEddystone,\r\n NotificationConfig,\r\n MonitoringOptions,\r\n} from \"./ExpoBeacon.types\";\r\n\r\ndeclare class ExpoBeaconModule extends NativeModule<ExpoBeaconModuleEvents> {\r\n /**\r\n * Start a one-shot iBeacon scan. Resolves with discovered beacons after scanDuration ms.\r\n *\r\n * Pass one or more UUIDs to scan for specific beacons (uses CoreLocation on iOS).\r\n * Pass an empty array or omit to perform a wildcard scan that discovers all nearby\r\n * iBeacons (uses CoreBluetooth on iOS — foreground only).\r\n *\r\n * @param uuids Proximity UUIDs to filter by. Empty/omitted = wildcard scan.\r\n * @param scanDuration Duration in ms (default 5000)\r\n */\r\n scanForBeaconsAsync(\r\n uuids?: string[],\r\n scanDuration?: number,\r\n ): Promise<BeaconScanResult[]>;\r\n\r\n /**\r\n * Start a one-shot Eddystone beacon scan using BLE.\r\n * Discovers Eddystone-UID and Eddystone-URL frames.\r\n *\r\n * @param scanDuration Duration in ms (default 5000)\r\n */\r\n scanForEddystonesAsync(\r\n scanDuration?: number,\r\n ): Promise<EddystoneScanResult[]>;\r\n\r\n /**\r\n * Register a beacon for persistent region monitoring.\r\n */\r\n pairBeacon(\r\n identifier: string,\r\n uuid: string,\r\n major: number,\r\n minor: number,\r\n ): void;\r\n\r\n /**\r\n * Remove a previously paired beacon.\r\n */\r\n unpairBeacon(identifier: string): void;\r\n\r\n /**\r\n * Return all currently paired beacons.\r\n */\r\n getPairedBeacons(): PairedBeacon[];\r\n\r\n /**\r\n * Register an Eddystone-UID beacon for persistent monitoring.\r\n */\r\n pairEddystone(\r\n identifier: string,\r\n namespace: string,\r\n instance: string,\r\n ): void;\r\n\r\n /**\r\n * Remove a previously paired Eddystone beacon.\r\n */\r\n unpairEddystone(identifier: string): void;\r\n\r\n /**\r\n * Return all currently paired Eddystone beacons.\r\n */\r\n getPairedEddystones(): PairedEddystone[];\r\n\r\n /**\r\n * Set persistent notification configuration. Settings are saved and applied to all\r\n * subsequent monitoring sessions until explicitly changed.\r\n */\r\n setNotificationConfig(config: NotificationConfig): void;\r\n\r\n /**\r\n * Start background region monitoring for all paired beacons.\r\n * On Android starts a foreground service.\r\n * On iOS starts CLLocationManager region monitoring.\r\n *\r\n * Accepts a plain number (backward-compatible maxDistance shorthand) or a\r\n * MonitoringOptions object with maxDistance and/or notification overrides.\r\n */\r\n startMonitoring(options?: MonitoringOptions | number): Promise<void>;\r\n\r\n /**\r\n * Stop background region monitoring.\r\n */\r\n stopMonitoring(): Promise<void>;\r\n\r\n /**\r\n * Start a continuous BLE scan. Fires `onBeaconFound` events as beacons are detected.\r\n * Call stopContinuousScan() to end the scan.\r\n */\r\n startContinuousScan(): void;\r\n\r\n /** Stop the continuous scan started by startContinuousScan(). */\r\n stopContinuousScan(): void;\r\n\r\n /** Request Bluetooth + Location permissions. Returns true if granted. */\r\n requestPermissionsAsync(): Promise<boolean>;\r\n}\r\n\r\nexport default requireNativeModule<ExpoBeaconModule>(\"ExpoBeacon\");\r\n"]}
@@ -1,9 +1,13 @@
1
- import type { ExpoBeaconModuleEvents, BeaconScanResult, PairedBeacon } from "./ExpoBeacon.types";
1
+ import type { ExpoBeaconModuleEvents, BeaconScanResult, EddystoneScanResult, PairedBeacon, PairedEddystone } from "./ExpoBeacon.types";
2
2
  declare const stub: {
3
3
  scanForBeaconsAsync: (_uuids: string[], _scanDuration?: number) => Promise<BeaconScanResult[]>;
4
+ scanForEddystonesAsync: (_scanDuration?: number) => Promise<EddystoneScanResult[]>;
4
5
  pairBeacon: (_identifier: string, _uuid: string, _major: number, _minor: number) => void;
5
6
  unpairBeacon: (_identifier: string) => void;
6
7
  getPairedBeacons: () => PairedBeacon[];
8
+ pairEddystone: (_identifier: string, _namespace: string, _instance: string) => void;
9
+ unpairEddystone: (_identifier: string) => void;
10
+ getPairedEddystones: () => PairedEddystone[];
7
11
  startMonitoring: () => Promise<void>;
8
12
  stopMonitoring: () => Promise<void>;
9
13
  requestPermissionsAsync: () => Promise<boolean>;
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoBeaconModule.web.d.ts","sourceRoot":"","sources":["../src/ExpoBeaconModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,gBAAgB,EAChB,YAAY,EACb,MAAM,oBAAoB,CAAC;AAM5B,QAAA,MAAM,IAAI;kCAEE,MAAM,EAAE,kBACA,MAAM,KACrB,OAAO,CAAC,gBAAgB,EAAE,CAAC;8BAEf,MAAM,SACZ,MAAM,UACL,MAAM,UACN,MAAM,KACb,IAAI;gCACqB,MAAM,KAAG,IAAI;4BACnB,YAAY,EAAE;2BACf,OAAO,CAAC,IAAI,CAAC;0BACd,OAAO,CAAC,IAAI,CAAC;mCACJ,OAAO,CAAC,OAAO,CAAC;8BACnB,MAAM,sBAAsB,aAAa,GAAG;;;qCAGrC,MAAM,sBAAsB;CAC9D,CAAC;AAEF,eAAe,IAAI,CAAC"}
1
+ {"version":3,"file":"ExpoBeaconModule.web.d.ts","sourceRoot":"","sources":["../src/ExpoBeaconModule.web.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EACtB,gBAAgB,EAChB,mBAAmB,EACnB,YAAY,EACZ,eAAe,EAChB,MAAM,oBAAoB,CAAC;AAM5B,QAAA,MAAM,IAAI;kCAEE,MAAM,EAAE,kBACA,MAAM,KACrB,OAAO,CAAC,gBAAgB,EAAE,CAAC;6CAEZ,MAAM,KACrB,OAAO,CAAC,mBAAmB,EAAE,CAAC;8BAElB,MAAM,SACZ,MAAM,UACL,MAAM,UACN,MAAM,KACb,IAAI;gCACqB,MAAM,KAAG,IAAI;4BACnB,YAAY,EAAE;iCAErB,MAAM,cACP,MAAM,aACP,MAAM,KAChB,IAAI;mCACwB,MAAM,KAAG,IAAI;+BACnB,eAAe,EAAE;2BACrB,OAAO,CAAC,IAAI,CAAC;0BACd,OAAO,CAAC,IAAI,CAAC;mCACJ,OAAO,CAAC,OAAO,CAAC;8BACnB,MAAM,sBAAsB,aAAa,GAAG;;;qCAGrC,MAAM,sBAAsB;CAC9D,CAAC;AAEF,eAAe,IAAI,CAAC"}
@@ -3,9 +3,13 @@ const notSupported = () => {
3
3
  };
4
4
  const stub = {
5
5
  scanForBeaconsAsync: (_uuids, _scanDuration) => notSupported(),
6
+ scanForEddystonesAsync: (_scanDuration) => notSupported(),
6
7
  pairBeacon: (_identifier, _uuid, _major, _minor) => notSupported(),
7
8
  unpairBeacon: (_identifier) => notSupported(),
8
9
  getPairedBeacons: () => notSupported(),
10
+ pairEddystone: (_identifier, _namespace, _instance) => notSupported(),
11
+ unpairEddystone: (_identifier) => notSupported(),
12
+ getPairedEddystones: () => notSupported(),
9
13
  startMonitoring: () => notSupported(),
10
14
  stopMonitoring: () => notSupported(),
11
15
  requestPermissionsAsync: () => notSupported(),
@@ -1 +1 @@
1
- {"version":3,"file":"ExpoBeaconModule.web.js","sourceRoot":"","sources":["../src/ExpoBeaconModule.web.ts"],"names":[],"mappings":"AAMA,MAAM,YAAY,GAAG,GAAU,EAAE;IAC/B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;AAC1D,CAAC,CAAC;AAEF,MAAM,IAAI,GAAG;IACX,mBAAmB,EAAE,CACnB,MAAgB,EAChB,aAAsB,EACO,EAAE,CAAC,YAAY,EAAE;IAChD,UAAU,EAAE,CACV,WAAmB,EACnB,KAAa,EACb,MAAc,EACd,MAAc,EACR,EAAE,CAAC,YAAY,EAAE;IACzB,YAAY,EAAE,CAAC,WAAmB,EAAQ,EAAE,CAAC,YAAY,EAAE;IAC3D,gBAAgB,EAAE,GAAmB,EAAE,CAAC,YAAY,EAAE;IACtD,eAAe,EAAE,GAAkB,EAAE,CAAC,YAAY,EAAE;IACpD,cAAc,EAAE,GAAkB,EAAE,CAAC,YAAY,EAAE;IACnD,uBAAuB,EAAE,GAAqB,EAAE,CAAC,YAAY,EAAE;IAC/D,WAAW,EAAE,CAAC,UAAwC,EAAE,SAAc,EAAE,EAAE,CAAC,CAAC;QAC1E,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC;KACjB,CAAC;IACF,kBAAkB,EAAE,CAAC,UAAwC,EAAE,EAAE,GAAE,CAAC;CACrE,CAAC;AAEF,eAAe,IAAI,CAAC","sourcesContent":["import type {\r\n ExpoBeaconModuleEvents,\r\n BeaconScanResult,\r\n PairedBeacon,\r\n} from \"./ExpoBeacon.types\";\r\n\r\nconst notSupported = (): never => {\r\n throw new Error(\"expo-beacon is not supported on web.\");\r\n};\r\n\r\nconst stub = {\r\n scanForBeaconsAsync: (\r\n _uuids: string[],\r\n _scanDuration?: number,\r\n ): Promise<BeaconScanResult[]> => notSupported(),\r\n pairBeacon: (\r\n _identifier: string,\r\n _uuid: string,\r\n _major: number,\r\n _minor: number,\r\n ): void => notSupported(),\r\n unpairBeacon: (_identifier: string): void => notSupported(),\r\n getPairedBeacons: (): PairedBeacon[] => notSupported(),\r\n startMonitoring: (): Promise<void> => notSupported(),\r\n stopMonitoring: (): Promise<void> => notSupported(),\r\n requestPermissionsAsync: (): Promise<boolean> => notSupported(),\r\n addListener: (_eventName: keyof ExpoBeaconModuleEvents, _listener: any) => ({\r\n remove: () => {},\r\n }),\r\n removeAllListeners: (_eventName: keyof ExpoBeaconModuleEvents) => {},\r\n};\r\n\r\nexport default stub;\r\n"]}
1
+ {"version":3,"file":"ExpoBeaconModule.web.js","sourceRoot":"","sources":["../src/ExpoBeaconModule.web.ts"],"names":[],"mappings":"AAQA,MAAM,YAAY,GAAG,GAAU,EAAE;IAC/B,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAC;AAC1D,CAAC,CAAC;AAEF,MAAM,IAAI,GAAG;IACX,mBAAmB,EAAE,CACnB,MAAgB,EAChB,aAAsB,EACO,EAAE,CAAC,YAAY,EAAE;IAChD,sBAAsB,EAAE,CACtB,aAAsB,EACU,EAAE,CAAC,YAAY,EAAE;IACnD,UAAU,EAAE,CACV,WAAmB,EACnB,KAAa,EACb,MAAc,EACd,MAAc,EACR,EAAE,CAAC,YAAY,EAAE;IACzB,YAAY,EAAE,CAAC,WAAmB,EAAQ,EAAE,CAAC,YAAY,EAAE;IAC3D,gBAAgB,EAAE,GAAmB,EAAE,CAAC,YAAY,EAAE;IACtD,aAAa,EAAE,CACb,WAAmB,EACnB,UAAkB,EAClB,SAAiB,EACX,EAAE,CAAC,YAAY,EAAE;IACzB,eAAe,EAAE,CAAC,WAAmB,EAAQ,EAAE,CAAC,YAAY,EAAE;IAC9D,mBAAmB,EAAE,GAAsB,EAAE,CAAC,YAAY,EAAE;IAC5D,eAAe,EAAE,GAAkB,EAAE,CAAC,YAAY,EAAE;IACpD,cAAc,EAAE,GAAkB,EAAE,CAAC,YAAY,EAAE;IACnD,uBAAuB,EAAE,GAAqB,EAAE,CAAC,YAAY,EAAE;IAC/D,WAAW,EAAE,CAAC,UAAwC,EAAE,SAAc,EAAE,EAAE,CAAC,CAAC;QAC1E,MAAM,EAAE,GAAG,EAAE,GAAE,CAAC;KACjB,CAAC;IACF,kBAAkB,EAAE,CAAC,UAAwC,EAAE,EAAE,GAAE,CAAC;CACrE,CAAC;AAEF,eAAe,IAAI,CAAC","sourcesContent":["import type {\r\n ExpoBeaconModuleEvents,\r\n BeaconScanResult,\r\n EddystoneScanResult,\r\n PairedBeacon,\r\n PairedEddystone,\r\n} from \"./ExpoBeacon.types\";\r\n\r\nconst notSupported = (): never => {\r\n throw new Error(\"expo-beacon is not supported on web.\");\r\n};\r\n\r\nconst stub = {\r\n scanForBeaconsAsync: (\r\n _uuids: string[],\r\n _scanDuration?: number,\r\n ): Promise<BeaconScanResult[]> => notSupported(),\r\n scanForEddystonesAsync: (\r\n _scanDuration?: number,\r\n ): Promise<EddystoneScanResult[]> => notSupported(),\r\n pairBeacon: (\r\n _identifier: string,\r\n _uuid: string,\r\n _major: number,\r\n _minor: number,\r\n ): void => notSupported(),\r\n unpairBeacon: (_identifier: string): void => notSupported(),\r\n getPairedBeacons: (): PairedBeacon[] => notSupported(),\r\n pairEddystone: (\r\n _identifier: string,\r\n _namespace: string,\r\n _instance: string,\r\n ): void => notSupported(),\r\n unpairEddystone: (_identifier: string): void => notSupported(),\r\n getPairedEddystones: (): PairedEddystone[] => notSupported(),\r\n startMonitoring: (): Promise<void> => notSupported(),\r\n stopMonitoring: (): Promise<void> => notSupported(),\r\n requestPermissionsAsync: (): Promise<boolean> => notSupported(),\r\n addListener: (_eventName: keyof ExpoBeaconModuleEvents, _listener: any) => ({\r\n remove: () => {},\r\n }),\r\n removeAllListeners: (_eventName: keyof ExpoBeaconModuleEvents) => {},\r\n};\r\n\r\nexport default stub;\r\n"]}
package/build/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { default } from "./ExpoBeaconModule";
2
- export type { BeaconScanResult, PairedBeacon, BeaconRegionEvent, BeaconDistanceEvent, ExpoBeaconModuleEvents, NotificationConfig, MonitoringOptions, BeaconNotificationConfig, ForegroundServiceConfig, NotificationChannelConfig, } from "./ExpoBeacon.types";
2
+ export type { BeaconScanResult, PairedBeacon, BeaconRegionEvent, BeaconDistanceEvent, ExpoBeaconModuleEvents, NotificationConfig, MonitoringOptions, BeaconNotificationConfig, ForegroundServiceConfig, NotificationChannelConfig, EddystoneFrameType, EddystoneScanResult, PairedEddystone, EddystoneRegionEvent, EddystoneDistanceEvent, } from "./ExpoBeacon.types";
3
3
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAG7C,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,yBAAyB,GAC1B,MAAM,oBAAoB,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAG7C,YAAY,EACV,gBAAgB,EAChB,YAAY,EACZ,iBAAiB,EACjB,mBAAmB,EACnB,sBAAsB,EACtB,kBAAkB,EAClB,iBAAiB,EACjB,wBAAwB,EACxB,uBAAuB,EACvB,yBAAyB,EACzB,kBAAkB,EAClB,mBAAmB,EACnB,eAAe,EACf,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,oBAAoB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC","sourcesContent":["// Native module (default export)\r\nexport { default } from \"./ExpoBeaconModule\";\r\n\r\n// All public types\r\nexport type {\r\n BeaconScanResult,\r\n PairedBeacon,\r\n BeaconRegionEvent,\r\n BeaconDistanceEvent,\r\n ExpoBeaconModuleEvents,\r\n NotificationConfig,\r\n MonitoringOptions,\r\n BeaconNotificationConfig,\r\n ForegroundServiceConfig,\r\n NotificationChannelConfig,\r\n} from \"./ExpoBeacon.types\";\r\n"]}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iCAAiC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC","sourcesContent":["// Native module (default export)\r\nexport { default } from \"./ExpoBeaconModule\";\r\n\r\n// All public types\r\nexport type {\r\n BeaconScanResult,\r\n PairedBeacon,\r\n BeaconRegionEvent,\r\n BeaconDistanceEvent,\r\n ExpoBeaconModuleEvents,\r\n NotificationConfig,\r\n MonitoringOptions,\r\n BeaconNotificationConfig,\r\n ForegroundServiceConfig,\r\n NotificationChannelConfig,\r\n EddystoneFrameType,\r\n EddystoneScanResult,\r\n PairedEddystone,\r\n EddystoneRegionEvent,\r\n EddystoneDistanceEvent,\r\n} from \"./ExpoBeacon.types\";\r\n"]}