spotny-sdk 0.4.0 → 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of spotny-sdk might be problematic. Click here for more details.

@@ -45,6 +45,8 @@ class SpotnySdkModule(private val reactContext: ReactApplicationContext) :
45
45
  // backendURL is fixed — not overridable by consumers.
46
46
  private val backendURL = "https://api.spotny.app"
47
47
  private var maxDetectionDistance = 8.0 // metres
48
+ /** Multiplier applied to raw BLE distance. Default 0.5 matches Kontakt.io -12 dBm beacons. */
49
+ private var distanceCorrectionFactor = 0.5
48
50
  /** Company/brand name identifying the SDK consumer (e.g. "nike"). */
49
51
  private var source: String? = null
50
52
 
@@ -140,6 +142,9 @@ class SpotnySdkModule(private val reactContext: ReactApplicationContext) :
140
142
  config?.getDouble("maxDetectionDistance").takeIf { config?.hasKey("maxDetectionDistance") == true }
141
143
  ?.let { maxDetectionDistance = it; Log.d(TAG, "maxDetectionDistance = $it m") }
142
144
  config?.getString("source")?.let { source = it; Log.d(TAG, "source = $it") }
145
+ config?.getDouble("distanceCorrectionFactor")
146
+ .takeIf { config?.hasKey("distanceCorrectionFactor") == true && it > 0 }
147
+ ?.let { distanceCorrectionFactor = it; Log.d(TAG, "distanceCorrectionFactor = $it") }
143
148
  promise.resolve("Configuration updated")
144
149
  }
145
150
 
@@ -210,7 +215,7 @@ class SpotnySdkModule(private val reactContext: ReactApplicationContext) :
210
215
  val jsBeacons = WritableNativeArray()
211
216
  for (beacon in beacons) {
212
217
  val raw = beacon.distance
213
- val adjusted = raw * 0.5
218
+ val adjusted = raw * distanceCorrectionFactor
214
219
  if (adjusted <= 0 || adjusted > maxDetectionDistance) continue
215
220
 
216
221
  val b = WritableNativeMap().apply {
@@ -236,7 +241,7 @@ class SpotnySdkModule(private val reactContext: ReactApplicationContext) :
236
241
  val major = beacon.id2?.toInt() ?: continue
237
242
  val minor = beacon.id3?.toInt() ?: continue
238
243
  val key = beaconKey(major, minor)
239
- val distance = beacon.distance * 0.5
244
+ val distance = beacon.distance * distanceCorrectionFactor
240
245
 
241
246
  if (distance <= 0 || distance > maxDetectionDistance) continue
242
247
 
@@ -360,7 +365,13 @@ class SpotnySdkModule(private val reactContext: ReactApplicationContext) :
360
365
 
361
366
  private fun cleanupAllState() {
362
367
  val deviceId = getDeviceId()
363
- activeCampaigns.keys.toList().forEach { cleanupBeacon(it, deviceId) }
368
+ // Stagger exit events to avoid firing N simultaneous network requests
369
+ val keys = activeCampaigns.keys.toList()
370
+ keys.forEachIndexed { index, key ->
371
+ android.os.Handler(android.os.Looper.getMainLooper()).postDelayed({
372
+ cleanupBeacon(key, deviceId)
373
+ }, index * 300L)
374
+ }
364
375
  }
365
376
 
366
377
  // ── Backend API ───────────────────────────────────────────────────────────
@@ -50,9 +50,17 @@ public class SpotnyBeaconScanner: NSObject {
50
50
  private let backendURL: String = "https://api.spotny.app"
51
51
  private let kontaktAPIKey: String = "mgrz08TOKNHafeY02cWIs9mxUHbynNQJ"
52
52
  private var maxDetectionDistance: Double = 8.0
53
+ /// Multiplier applied to raw RSSI-derived distance to compensate for low TX power.
54
+ /// Overridable via configure(). Default 0.5 matches Kontakt.io -12 dBm beacons.
55
+ private var distanceCorrectionFactor: Double = 0.5
53
56
  /// Company/brand name that identifies the SDK consumer (e.g. "nike").
54
57
  private var source: String?
55
58
 
59
+ // ── Session TTL ────────────────────────────────────────────────────────────
60
+ /// Sessions older than this when the app resumes are considered stale (crash / force-quit).
61
+ private let sessionTTL: TimeInterval = 24 * 3600 // 24 hours
62
+ private var lastSessionHeartbeat: Date = .distantPast
63
+
56
64
  // ── Beacon UUID (standard Kontakt.io default) ─────────────────────────────
57
65
  private let beaconUUID = UUID(uuidString: "f7826da6-4fa2-4e98-8024-bc5b71e0893e")!
58
66
 
@@ -107,6 +115,15 @@ public class SpotnyBeaconScanner: NSObject {
107
115
 
108
116
  private func resumeStoredSession() {
109
117
  guard let stored = UserDefaults.standard.string(forKey: "SpotnySDK_userUUID") else { return }
118
+ // Discard sessions older than sessionTTL — stale after a crash / force-quit
119
+ if let ts = UserDefaults.standard.object(forKey: "SpotnySDK_sessionTimestamp") as? Double {
120
+ let age = Date().timeIntervalSince1970 - ts
121
+ if age > sessionTTL {
122
+ print("⚠️ SpotnySDK: Stale session (\(Int(age / 3600))h old) — discarding")
123
+ clearStoredSession()
124
+ return
125
+ }
126
+ }
110
127
  currentUserUUID = stored
111
128
  userId = UserDefaults.standard.object(forKey: "SpotnySDK_userId") as? Int
112
129
  print("🔄 SpotnySDK: Resuming session for UUID: \(stored)")
@@ -114,6 +131,13 @@ public class SpotnyBeaconScanner: NSObject {
114
131
  scanning = true
115
132
  }
116
133
 
134
+ private func clearStoredSession() {
135
+ UserDefaults.standard.removeObject(forKey: "SpotnySDK_userUUID")
136
+ UserDefaults.standard.removeObject(forKey: "SpotnySDK_userId")
137
+ UserDefaults.standard.removeObject(forKey: "SpotnySDK_sessionTimestamp")
138
+ UserDefaults.standard.synchronize()
139
+ }
140
+
117
141
  // MARK: - ObjC-Exposed Methods (called from SpotnySdk.mm)
118
142
 
119
143
  @objc
@@ -137,6 +161,7 @@ public class SpotnyBeaconScanner: NSObject {
137
161
  } else {
138
162
  UserDefaults.standard.removeObject(forKey: "SpotnySDK_userId")
139
163
  }
164
+ UserDefaults.standard.set(Date().timeIntervalSince1970, forKey: "SpotnySDK_sessionTimestamp")
140
165
  UserDefaults.standard.synchronize()
141
166
 
142
167
  let status = locationManager.authorizationStatus
@@ -159,9 +184,7 @@ public class SpotnyBeaconScanner: NSObject {
159
184
  beaconManager.stopRangingBeaconsInAllRegions()
160
185
  cleanupAllProximityState()
161
186
 
162
- UserDefaults.standard.removeObject(forKey: "SpotnySDK_userUUID")
163
- UserDefaults.standard.removeObject(forKey: "SpotnySDK_userId")
164
- UserDefaults.standard.synchronize()
187
+ clearStoredSession()
165
188
 
166
189
  scanning = false
167
190
  currentUserUUID = nil
@@ -193,6 +216,10 @@ public class SpotnyBeaconScanner: NSObject {
193
216
  source = src
194
217
  print("⚙️ SpotnySDK: source = \(src)")
195
218
  }
219
+ if let factor = config["distanceCorrectionFactor"] as? Double, factor > 0 {
220
+ distanceCorrectionFactor = factor
221
+ print("⚙️ SpotnySDK: distanceCorrectionFactor = \(factor)")
222
+ }
196
223
  resolve("Configuration updated")
197
224
  }
198
225
 
@@ -578,7 +605,13 @@ public class SpotnyBeaconScanner: NSObject {
578
605
 
579
606
  private func cleanupAllProximityState() {
580
607
  let deviceId = getDeviceId()
581
- for key in activeCampaigns.keys { cleanupBeacon(key, deviceId: deviceId) }
608
+ // Stagger exit events to avoid firing N simultaneous network requests
609
+ let keys = Array(activeCampaigns.keys)
610
+ for (index, key) in keys.enumerated() {
611
+ DispatchQueue.main.asyncAfter(deadline: .now() + Double(index) * 0.3) { [weak self] in
612
+ self?.cleanupBeacon(key, deviceId: deviceId)
613
+ }
614
+ }
582
615
  }
583
616
  }
584
617
 
@@ -608,10 +641,16 @@ extension SpotnyBeaconScanner: KTKBeaconManagerDelegate {
608
641
  let deviceId = getDeviceId()
609
642
  let now = Date()
610
643
 
644
+ // Refresh session heartbeat every 60 s to prevent TTL expiry on a live session
645
+ if now.timeIntervalSince(lastSessionHeartbeat) >= 60 {
646
+ UserDefaults.standard.set(now.timeIntervalSince1970, forKey: "SpotnySDK_sessionTimestamp")
647
+ lastSessionHeartbeat = now
648
+ }
649
+
611
650
  // Build the JS event payload for ALL ranged beacons
612
651
  let beaconPayload: [[String: Any]] = beacons.compactMap { beacon in
613
652
  let raw = beacon.accuracy
614
- let adjusted = raw * 0.5 // compensate for low TX power (-12 dBm)
653
+ let adjusted = raw * distanceCorrectionFactor
615
654
  guard adjusted > 0 && adjusted <= maxDetectionDistance else { return nil }
616
655
  return [
617
656
  "uuid": beacon.proximityUUID.uuidString,
@@ -633,7 +672,7 @@ extension SpotnyBeaconScanner: KTKBeaconManagerDelegate {
633
672
  let minor = beacon.minor.intValue
634
673
  let key = beaconKey(major: major, minor: minor)
635
674
  let raw = beacon.accuracy
636
- let distance = raw * 0.5
675
+ let distance = raw * distanceCorrectionFactor
637
676
 
638
677
  guard distance > 0 && distance <= maxDetectionDistance else { continue }
639
678
 
@@ -678,8 +717,6 @@ extension SpotnyBeaconScanner: KTKBeaconManagerDelegate {
678
717
  var bg: UIBackgroundTaskIdentifier = .invalid
679
718
  bg = UIApplication.shared.beginBackgroundTask { UIApplication.shared.endBackgroundTask(bg); bg = .invalid }
680
719
 
681
- beaconManager.startRangingBeacons(in: region)
682
-
683
720
  // Parse major/minor from named regions (e.g. "SpotnySDK_52885_35127")
684
721
  let parts = region.identifier.components(separatedBy: "_")
685
722
  if parts.count == 3, let major = Int(parts[1]), let minor = Int(parts[2]) {
@@ -1 +1 @@
1
- {"version":3,"names":["NativeEventEmitter","NativeModules","NativeSpotnySdk","SpotnyEvents","ON_BEACONS_RANGED","ON_BEACON_REGION_EVENT","eventEmitter","SpotnySdk","startScanner","userUUID","userId","stopScanner","isScanning","configure","config","requestNotificationPermissions","getDebugLogs","clearDebugLogs","setDebounceInterval","interval","clearDebounceCache","getDebounceStatus","addBeaconsRangedListener","callback","addListener","addBeaconRegionListener"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,kBAAkB,EAAEC,aAAa,QAAQ,cAAc;AAChE,OAAOC,eAAe,MAAM,sBAAmB;;AAE/C;AACA,OAAO,MAAMC,YAAY,GAAG;EAC1BC,iBAAiB,EAAE,iBAAiB;EACpCC,sBAAsB,EAAE;AAC1B,CAAU;;AAEV;;AAgCA;AACA,MAAMC,YAAY,GAAG,IAAIN,kBAAkB,CAACC,aAAa,CAACM,SAAS,CAAC;;AAEpE;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,YAAYA,CAC1BC,QAAgB,EAChBC,MAAsB,EACL;EACjB,OAAOR,eAAe,CAACM,YAAY,CAACC,QAAQ,EAAEC,MAAM,IAAI,IAAI,CAAC;AAC/D;;AAEA;AACA,OAAO,SAASC,WAAWA,CAAA,EAAoB;EAC7C,OAAOT,eAAe,CAACS,WAAW,CAAC,CAAC;AACtC;;AAEA;AACA,OAAO,SAASC,UAAUA,CAAA,EAAqB;EAC7C,OAAOV,eAAe,CAACU,UAAU,CAAC,CAAC;AACrC;;AAEA;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASC,SAASA,CAACC,MAAuB,EAAmB;EAClE,OAAOZ,eAAe,CAACW,SAAS,CAACC,MAAgB,CAAC;AACpD;;AAEA;;AAEA;AACA,OAAO,SAASC,8BAA8BA,CAAA,EAAoB;EAChE,OAAOb,eAAe,CAACa,8BAA8B,CAAC,CAAC;AACzD;;AAEA;;AAEA;AACA,OAAO,SAASC,YAAYA,CAAA,EAAoB;EAC9C,OAAOd,eAAe,CAACc,YAAY,CAAC,CAAC;AACvC;;AAEA;AACA,OAAO,SAASC,cAAcA,CAAA,EAAoB;EAChD,OAAOf,eAAe,CAACe,cAAc,CAAC,CAAC;AACzC;;AAEA;;AAEA;AACA,OAAO,SAASC,mBAAmBA,CAACC,QAAgB,EAAmB;EACrE,OAAOjB,eAAe,CAACgB,mBAAmB,CAACC,QAAQ,CAAC;AACtD;;AAEA;AACA,OAAO,SAASC,kBAAkBA,CAAA,EAAoB;EACpD,OAAOlB,eAAe,CAACkB,kBAAkB,CAAC,CAAC;AAC7C;;AAEA;AACA,OAAO,SAASC,iBAAiBA,CAAA,EAAoB;EACnD,OAAOnB,eAAe,CAACmB,iBAAiB,CAAC,CAAC;AAC5C;;AAEA;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASC,wBAAwBA,CACtCC,QAA4C,EAC5C;EACA,OAAOjB,YAAY,CAACkB,WAAW,CAC7BrB,YAAY,CAACC,iBAAiB,EAC9BmB,QACF,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASE,uBAAuBA,CACrCF,QAA4C,EAC5C;EACA,OAAOjB,YAAY,CAACkB,WAAW,CAC7BrB,YAAY,CAACE,sBAAsB,EACnCkB,QACF,CAAC;AACH","ignoreList":[]}
1
+ {"version":3,"names":["NativeEventEmitter","NativeModules","NativeSpotnySdk","SpotnyEvents","ON_BEACONS_RANGED","ON_BEACON_REGION_EVENT","eventEmitter","SpotnySdk","startScanner","userUUID","userId","stopScanner","isScanning","configure","config","requestNotificationPermissions","getDebugLogs","clearDebugLogs","setDebounceInterval","interval","clearDebounceCache","getDebounceStatus","addBeaconsRangedListener","callback","addListener","addBeaconRegionListener"],"sourceRoot":"../../src","sources":["index.tsx"],"mappings":";;AAAA,SAASA,kBAAkB,EAAEC,aAAa,QAAQ,cAAc;AAChE,OAAOC,eAAe,MAAM,sBAAmB;;AAE/C;AACA,OAAO,MAAMC,YAAY,GAAG;EAC1BC,iBAAiB,EAAE,iBAAiB;EACpCC,sBAAsB,EAAE;AAC1B,CAAU;;AAEV;;AAqCA;AACA,MAAMC,YAAY,GAAG,IAAIN,kBAAkB,CAACC,aAAa,CAACM,SAAS,CAAC;;AAEpE;;AAEA;AACA;AACA;AACA;AACA;AACA,OAAO,SAASC,YAAYA,CAC1BC,QAAgB,EAChBC,MAAsB,EACL;EACjB,OAAOR,eAAe,CAACM,YAAY,CAACC,QAAQ,EAAEC,MAAM,IAAI,IAAI,CAAC;AAC/D;;AAEA;AACA,OAAO,SAASC,WAAWA,CAAA,EAAoB;EAC7C,OAAOT,eAAe,CAACS,WAAW,CAAC,CAAC;AACtC;;AAEA;AACA,OAAO,SAASC,UAAUA,CAAA,EAAqB;EAC7C,OAAOV,eAAe,CAACU,UAAU,CAAC,CAAC;AACrC;;AAEA;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASC,SAASA,CAACC,MAAuB,EAAmB;EAClE,OAAOZ,eAAe,CAACW,SAAS,CAACC,MAAgB,CAAC;AACpD;;AAEA;;AAEA;AACA,OAAO,SAASC,8BAA8BA,CAAA,EAAoB;EAChE,OAAOb,eAAe,CAACa,8BAA8B,CAAC,CAAC;AACzD;;AAEA;;AAEA;AACA,OAAO,SAASC,YAAYA,CAAA,EAAoB;EAC9C,OAAOd,eAAe,CAACc,YAAY,CAAC,CAAC;AACvC;;AAEA;AACA,OAAO,SAASC,cAAcA,CAAA,EAAoB;EAChD,OAAOf,eAAe,CAACe,cAAc,CAAC,CAAC;AACzC;;AAEA;;AAEA;AACA,OAAO,SAASC,mBAAmBA,CAACC,QAAgB,EAAmB;EACrE,OAAOjB,eAAe,CAACgB,mBAAmB,CAACC,QAAQ,CAAC;AACtD;;AAEA;AACA,OAAO,SAASC,kBAAkBA,CAAA,EAAoB;EACpD,OAAOlB,eAAe,CAACkB,kBAAkB,CAAC,CAAC;AAC7C;;AAEA;AACA,OAAO,SAASC,iBAAiBA,CAAA,EAAoB;EACnD,OAAOnB,eAAe,CAACmB,iBAAiB,CAAC,CAAC;AAC5C;;AAEA;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASC,wBAAwBA,CACtCC,QAA4C,EAC5C;EACA,OAAOjB,YAAY,CAACkB,WAAW,CAC7BrB,YAAY,CAACC,iBAAiB,EAC9BmB,QACF,CAAC;AACH;;AAEA;AACA;AACA;AACA;AACA,OAAO,SAASE,uBAAuBA,CACrCF,QAA4C,EAC5C;EACA,OAAOjB,YAAY,CAACkB,WAAW,CAC7BrB,YAAY,CAACE,sBAAsB,EACnCkB,QACF,CAAC;AACH","ignoreList":[]}
@@ -27,6 +27,11 @@ export type SpotnySdkConfig = {
27
27
  maxDetectionDistance?: number;
28
28
  /** Identifier for your brand or app (e.g. 'nike'). */
29
29
  source?: string;
30
+ /**
31
+ * Multiplier applied to raw RSSI-derived distance to compensate for device
32
+ * TX power variance (default: 0.5, tuned for Kontakt.io -12 dBm beacons).
33
+ */
34
+ distanceCorrectionFactor?: number;
30
35
  };
31
36
  /**
32
37
  * Start beacon scanning.
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAIX,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,YAAY,CAAC;IACvC,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,8DAA8D;IAC9D,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB,CAAC;AAOF;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GACrB,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,mDAAmD;AACnD,wBAAgB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAE7C;AAED,uDAAuD;AACvD,wBAAgB,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,CAE7C;AAID;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAElE;AAID,gEAAgE;AAChE,wBAAgB,8BAA8B,IAAI,OAAO,CAAC,MAAM,CAAC,CAEhE;AAID,yCAAyC;AACzC,wBAAgB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAE9C;AAED,2CAA2C;AAC3C,wBAAgB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAEhD;AAID,gEAAgE;AAChE,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAErE;AAED,2DAA2D;AAC3D,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAEpD;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAEnD;AAID;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,4CAM7C;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,4CAM7C"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/index.tsx"],"names":[],"mappings":"AAIA,eAAO,MAAM,YAAY;;;CAGf,CAAC;AAIX,MAAM,MAAM,UAAU,GAAG;IACvB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,mCAAmC;IACnC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,+CAA+C;IAC/C,SAAS,EAAE,MAAM,CAAC;CACnB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,UAAU,EAAE,CAAC;IACtB,MAAM,EAAE,MAAM,CAAC;CAChB,CAAC;AAEF,MAAM,MAAM,iBAAiB,GAAG;IAC9B,MAAM,EAAE,MAAM,CAAC;IACf,sCAAsC;IACtC,KAAK,EAAE,OAAO,GAAG,MAAM,GAAG,YAAY,CAAC;IACvC,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,SAAS,CAAC;CAC1C,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,8DAA8D;IAC9D,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,sDAAsD;IACtD,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB;;;OAGG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC,CAAC;AAOF;;;;GAIG;AACH,wBAAgB,YAAY,CAC1B,QAAQ,EAAE,MAAM,EAChB,MAAM,CAAC,EAAE,MAAM,GAAG,IAAI,GACrB,OAAO,CAAC,MAAM,CAAC,CAEjB;AAED,mDAAmD;AACnD,wBAAgB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAE7C;AAED,uDAAuD;AACvD,wBAAgB,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,CAE7C;AAID;;;GAGG;AACH,wBAAgB,SAAS,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAElE;AAID,gEAAgE;AAChE,wBAAgB,8BAA8B,IAAI,OAAO,CAAC,MAAM,CAAC,CAEhE;AAID,yCAAyC;AACzC,wBAAgB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAE9C;AAED,2CAA2C;AAC3C,wBAAgB,cAAc,IAAI,OAAO,CAAC,MAAM,CAAC,CAEhD;AAID,gEAAgE;AAChE,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAErE;AAED,2DAA2D;AAC3D,wBAAgB,kBAAkB,IAAI,OAAO,CAAC,MAAM,CAAC,CAEpD;AAED,kEAAkE;AAClE,wBAAgB,iBAAiB,IAAI,OAAO,CAAC,MAAM,CAAC,CAEnD;AAID;;;GAGG;AACH,wBAAgB,wBAAwB,CACtC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,4CAM7C;AAED;;;GAGG;AACH,wBAAgB,uBAAuB,CACrC,QAAQ,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,IAAI,4CAM7C"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spotny-sdk",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "description": "Beacon Scanner",
5
5
  "main": "./lib/module/index.js",
6
6
  "types": "./lib/typescript/src/index.d.ts",
package/src/index.tsx CHANGED
@@ -37,6 +37,11 @@ export type SpotnySdkConfig = {
37
37
  maxDetectionDistance?: number;
38
38
  /** Identifier for your brand or app (e.g. 'nike'). */
39
39
  source?: string;
40
+ /**
41
+ * Multiplier applied to raw RSSI-derived distance to compensate for device
42
+ * TX power variance (default: 0.5, tuned for Kontakt.io -12 dBm beacons).
43
+ */
44
+ distanceCorrectionFactor?: number;
40
45
  };
41
46
 
42
47
  // ── Internal event emitter ───────────────────────────────────────────────────