spotny-sdk 1.0.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -68,7 +68,7 @@ export default function App() {
|
|
|
68
68
|
initialize({
|
|
69
69
|
token: 'YOUR_SDK_TOKEN', // from your Spotny dashboard
|
|
70
70
|
apiKey: 'your-brand-key', // identifies your app/brand
|
|
71
|
-
|
|
71
|
+
identifierId: currentUser.id, // your authenticated user ID
|
|
72
72
|
maxDetectionDistance: 10,
|
|
73
73
|
});
|
|
74
74
|
|
|
@@ -110,23 +110,23 @@ export default function App() {
|
|
|
110
110
|
|
|
111
111
|
**Must be called before any other SDK function.** Authenticates with the Spotny backend and obtains a session JWT that is automatically used for all subsequent API calls.
|
|
112
112
|
|
|
113
|
-
| Option | Type | Default | Description
|
|
114
|
-
| -------------------------- | -------- | ------------ |
|
|
115
|
-
| `token` | `string` | **required** | SDK token issued by Spotny for your app. Verified against the backend — rejects with `UNAUTHORIZED` if invalid.
|
|
116
|
-
| `apiKey` | `string` | **required** | Identifies your brand or app (e.g. `'nike'`). Sent to the backend during verification.
|
|
117
|
-
| `
|
|
118
|
-
| `maxDetectionDistance` | `number` | `8.0` | Maximum detection radius in metres. Beacons beyond this are ignored.
|
|
119
|
-
| `distanceCorrectionFactor` | `number` | `0.5` | Multiplier applied to raw RSSI distance. Tune for your beacon TX power.
|
|
113
|
+
| Option | Type | Default | Description |
|
|
114
|
+
| -------------------------- | -------- | ------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
115
|
+
| `token` | `string` | **required** | SDK token issued by Spotny for your app. Verified against the backend — rejects with `UNAUTHORIZED` if invalid. |
|
|
116
|
+
| `apiKey` | `string` | **required** | Identifies your brand or app (e.g. `'nike'`). Sent to the backend during verification. |
|
|
117
|
+
| `identifierId` | `string` | **required** | Unique identifier for the authenticated user (e.g. database UUID, hashed email). Embedded in the session JWT so all tracking events are tied to this user. |
|
|
118
|
+
| `maxDetectionDistance` | `number` | `8.0` | Maximum detection radius in metres. Beacons beyond this are ignored. |
|
|
119
|
+
| `distanceCorrectionFactor` | `number` | `0.5` | Multiplier applied to raw RSSI distance. Tune for your beacon TX power. |
|
|
120
120
|
|
|
121
121
|
Returns `Promise<string>`. **Rejects** if any required field is missing, the token is invalid, or the network request fails — handle the error before calling `startScanner()`.
|
|
122
122
|
|
|
123
|
-
> **Note:** The SDK is designed for authenticated (logged-in) users. Call `initialize()` after the user has signed in so their `
|
|
123
|
+
> **Note:** The SDK is designed for authenticated (logged-in) users. Call `initialize()` after the user has signed in so their `identifierId` is available.
|
|
124
124
|
|
|
125
125
|
```ts
|
|
126
126
|
await initialize({
|
|
127
127
|
token: 'YOUR_SDK_TOKEN',
|
|
128
128
|
apiKey: 'nike',
|
|
129
|
-
|
|
129
|
+
identifierId: currentUser.id,
|
|
130
130
|
maxDetectionDistance: 10,
|
|
131
131
|
distanceCorrectionFactor: 0.5,
|
|
132
132
|
});
|
|
@@ -274,7 +274,7 @@ Returns `Promise<Object>`.
|
|
|
274
274
|
5. `IMPRESSION_HEARTBEAT` events are sent every 10 s when the user is within 2 m of an active campaign.
|
|
275
275
|
6. On exit, `PROXIMITY_EXIT` is sent and all state is cleaned up.
|
|
276
276
|
|
|
277
|
-
All events are tied to the authenticated `
|
|
277
|
+
All events are tied to the authenticated `identifierId` supplied during `initialize()` — no additional identity calls are required.
|
|
278
278
|
|
|
279
279
|
---
|
|
280
280
|
|
|
@@ -38,12 +38,13 @@ class SpotnySdkModule(private val reactContext: ReactApplicationContext) :
|
|
|
38
38
|
|
|
39
39
|
// ── Session state ─────────────────────────────────────────────────────────
|
|
40
40
|
@Volatile private var scanning = false
|
|
41
|
-
/** Authenticated
|
|
42
|
-
private var
|
|
41
|
+
/** Authenticated identifier — required at initialize(). Embedded in JWT via /api/app/sdk/verify. */
|
|
42
|
+
private var identifierId: String? = null
|
|
43
43
|
|
|
44
44
|
// ── Configuration ─────────────────────────────────────────────────────────
|
|
45
|
-
// backendURL
|
|
45
|
+
// backendURL and apiBasePath are fixed — not overridable by consumers.
|
|
46
46
|
private val backendURL = "https://api.spotny.app"
|
|
47
|
+
private val apiBasePath = "/api/app/sdk"
|
|
47
48
|
private var maxDetectionDistance = 8.0 // metres
|
|
48
49
|
/** Multiplier applied to raw BLE distance. Default 0.5 matches Kontakt.io -12 dBm beacons. */
|
|
49
50
|
private var distanceCorrectionFactor = 0.5
|
|
@@ -101,7 +102,7 @@ class SpotnySdkModule(private val reactContext: ReactApplicationContext) :
|
|
|
101
102
|
sdkToken = prefs.getString("jwt", null)
|
|
102
103
|
sdkCredential = prefs.getString("sdkCredential", null)
|
|
103
104
|
apiKey = prefs.getString("sdkApiKey", null)
|
|
104
|
-
|
|
105
|
+
identifierId = prefs.getString("sdkIdentifierId", null)
|
|
105
106
|
val expiry = prefs.getLong("jwtExpiry", -1L).takeIf { it > 0 }
|
|
106
107
|
if (expiry != null) sdkTokenExpiry = expiry
|
|
107
108
|
Log.d(TAG, "Resuming session (device: ${getDeviceId()})")
|
|
@@ -161,17 +162,17 @@ class SpotnySdkModule(private val reactContext: ReactApplicationContext) :
|
|
|
161
162
|
promise.reject("MISSING_API_KEY", "initialize() requires an apiKey")
|
|
162
163
|
return
|
|
163
164
|
}
|
|
164
|
-
config?.getString("
|
|
165
|
-
val uid =
|
|
165
|
+
config?.getString("identifierId")?.takeIf { it.isNotBlank() }?.let { identifierId = it }
|
|
166
|
+
val uid = identifierId?.takeIf { it.isNotBlank() }
|
|
166
167
|
if (uid == null) {
|
|
167
|
-
promise.reject("
|
|
168
|
+
promise.reject("MISSING_IDENTIFIER_ID", "initialize() requires an identifierId")
|
|
168
169
|
return
|
|
169
170
|
}
|
|
170
171
|
|
|
171
|
-
// Send token + apiKey +
|
|
172
|
+
// Send token + apiKey + identifierId to backend — response returns a JWT used for all subsequent calls
|
|
172
173
|
// sdkToken is null here so no Authorization header is injected on this call
|
|
173
174
|
val verifyPayload = mapOf("token" to token, "api_key" to key, "user_id" to uid)
|
|
174
|
-
post("/
|
|
175
|
+
post("$apiBasePath/verify", verifyPayload) { status, body ->
|
|
175
176
|
when {
|
|
176
177
|
status in 200..299 -> {
|
|
177
178
|
val verifyJson = try { parseJsonObject(body) } catch (_: Exception) { null }
|
|
@@ -438,7 +439,7 @@ class SpotnySdkModule(private val reactContext: ReactApplicationContext) :
|
|
|
438
439
|
sdkToken?.let { prefs.putString("jwt", it) }
|
|
439
440
|
sdkCredential?.let { prefs.putString("sdkCredential", it) }
|
|
440
441
|
apiKey?.let { prefs.putString("sdkApiKey", it) }
|
|
441
|
-
|
|
442
|
+
identifierId?.let { prefs.putString("sdkIdentifierId", it) }
|
|
442
443
|
sdkTokenExpiry?.let { prefs.putLong("jwtExpiry", it) }
|
|
443
444
|
prefs.apply()
|
|
444
445
|
}
|
|
@@ -448,14 +449,14 @@ class SpotnySdkModule(private val reactContext: ReactApplicationContext) :
|
|
|
448
449
|
val credential = sdkCredential ?: return false
|
|
449
450
|
val key = apiKey ?: return false
|
|
450
451
|
return try {
|
|
451
|
-
val conn = (URL("$backendURL/
|
|
452
|
+
val conn = (URL("$backendURL$apiBasePath/verify").openConnection() as HttpURLConnection).apply {
|
|
452
453
|
requestMethod = "POST"
|
|
453
454
|
setRequestProperty("Content-Type", "application/json")
|
|
454
455
|
connectTimeout = 10_000
|
|
455
456
|
readTimeout = 10_000
|
|
456
457
|
doOutput = true
|
|
457
458
|
}
|
|
458
|
-
conn.outputStream.use { it.write(buildJsonString(mapOf("token" to credential, "api_key" to key, "user_id" to (
|
|
459
|
+
conn.outputStream.use { it.write(buildJsonString(mapOf("token" to credential, "api_key" to key, "user_id" to (identifierId ?: ""))).toByteArray()) }
|
|
459
460
|
val status = conn.responseCode
|
|
460
461
|
val response = try { conn.inputStream.bufferedReader().readText() }
|
|
461
462
|
catch (_: Exception) { conn.errorStream?.bufferedReader()?.readText() ?: "" }
|
|
@@ -485,7 +486,7 @@ class SpotnySdkModule(private val reactContext: ReactApplicationContext) :
|
|
|
485
486
|
) {
|
|
486
487
|
ioExecutor.execute {
|
|
487
488
|
// Auto-refresh JWT before every call except verify itself
|
|
488
|
-
if (endpoint != "/
|
|
489
|
+
if (endpoint != "$apiBasePath/verify" && isTokenExpired()) {
|
|
489
490
|
if (!refreshJWTBlocking()) {
|
|
490
491
|
reactContext.runOnUiQueueThread { completion(-1, "") }
|
|
491
492
|
return@execute
|
|
@@ -547,7 +548,7 @@ class SpotnySdkModule(private val reactContext: ReactApplicationContext) :
|
|
|
547
548
|
|
|
548
549
|
val payload = mutableMapOf<String, Any?>("beacon_id" to key)
|
|
549
550
|
|
|
550
|
-
post("/
|
|
551
|
+
post("$apiBasePath/distribute", payload) { status, body ->
|
|
551
552
|
fetchInProgress[key] = false
|
|
552
553
|
if (status != 200) {
|
|
553
554
|
Log.w(TAG, "Campaign fetch status $status for beacon $key")
|
|
@@ -639,10 +640,10 @@ class SpotnySdkModule(private val reactContext: ReactApplicationContext) :
|
|
|
639
640
|
}
|
|
640
641
|
|
|
641
642
|
private fun sendProximity(eventType: String, key: String, distance: Double) =
|
|
642
|
-
sendTracking(eventType, key, distance, "/
|
|
643
|
+
sendTracking(eventType, key, distance, "$apiBasePath/proximity")
|
|
643
644
|
|
|
644
645
|
private fun sendImpression(key: String, distance: Double) =
|
|
645
|
-
sendTracking("IMPRESSION_HEARTBEAT", key, distance, "/
|
|
646
|
+
sendTracking("IMPRESSION_HEARTBEAT", key, distance, "$apiBasePath/track")
|
|
646
647
|
|
|
647
648
|
// ── Minimal JSON parser (avoids org.json / GSON dependency) ──────────────
|
|
648
649
|
// Only handles flat and one-level-deep objects. For this SDK, that is enough.
|
|
@@ -42,8 +42,8 @@ public class SpotnyBeaconScanner: NSObject {
|
|
|
42
42
|
|
|
43
43
|
// ── Session state ─────────────────────────────────────────────────────────
|
|
44
44
|
private var scanning: Bool = false
|
|
45
|
-
/// Authenticated
|
|
46
|
-
private var
|
|
45
|
+
/// Authenticated identifier — required at initialize(). Embedded in the JWT via /api/app/sdk/verify.
|
|
46
|
+
private var identifierId: String?
|
|
47
47
|
|
|
48
48
|
// ── JS event deduplication ─────────────────────────────────────────
|
|
49
49
|
/// Signature of the last emitted `onBeaconsRanged` payload (sorted major_minor_proximity).
|
|
@@ -54,6 +54,7 @@ public class SpotnyBeaconScanner: NSObject {
|
|
|
54
54
|
// ── Configuration ────────────────────────────────────────────────────────────
|
|
55
55
|
// backendURL and kontaktAPIKey are fixed — not overridable by consumers.
|
|
56
56
|
private let backendURL: String = "https://api.spotny.app"
|
|
57
|
+
private let apiBasePath: String = "/api/app/sdk"
|
|
57
58
|
private let kontaktAPIKey: String = "mgrz08TOKNHafeY02cWIs9mxUHbynNQJ"
|
|
58
59
|
private var maxDetectionDistance: Double = 8.0
|
|
59
60
|
/// Multiplier applied to raw RSSI-derived distance to compensate for low TX power.
|
|
@@ -141,7 +142,7 @@ public class SpotnyBeaconScanner: NSObject {
|
|
|
141
142
|
sdkToken = keychainRead(key: "SpotnySDK_jwt")
|
|
142
143
|
sdkCredential = keychainRead(key: "SpotnySDK_sdkCredential")
|
|
143
144
|
apiKey = keychainRead(key: "SpotnySDK_apiKey")
|
|
144
|
-
|
|
145
|
+
identifierId = keychainRead(key: "SpotnySDK_identifierId")
|
|
145
146
|
if let expiryStr = keychainRead(key: "SpotnySDK_jwtExpiry"), let ts = Double(expiryStr) {
|
|
146
147
|
sdkTokenExpiry = Date(timeIntervalSince1970: ts)
|
|
147
148
|
}
|
|
@@ -226,8 +227,8 @@ public class SpotnyBeaconScanner: NSObject {
|
|
|
226
227
|
distanceCorrectionFactor = factor
|
|
227
228
|
print("⚙️ SpotnySDK: distanceCorrectionFactor = \(factor)")
|
|
228
229
|
}
|
|
229
|
-
if let uid = config["
|
|
230
|
-
|
|
230
|
+
if let uid = config["identifierId"] as? String, !uid.isEmpty {
|
|
231
|
+
identifierId = uid
|
|
231
232
|
}
|
|
232
233
|
guard let token = config["token"] as? String, !token.isEmpty else {
|
|
233
234
|
reject("MISSING_TOKEN", "initialize() requires a token", nil)
|
|
@@ -237,15 +238,15 @@ public class SpotnyBeaconScanner: NSObject {
|
|
|
237
238
|
reject("MISSING_API_KEY", "initialize() requires an apiKey", nil)
|
|
238
239
|
return
|
|
239
240
|
}
|
|
240
|
-
guard let uid =
|
|
241
|
-
reject("
|
|
241
|
+
guard let uid = identifierId, !uid.isEmpty else {
|
|
242
|
+
reject("MISSING_IDENTIFIER_ID", "initialize() requires an identifierId", nil)
|
|
242
243
|
return
|
|
243
244
|
}
|
|
244
245
|
|
|
245
|
-
// Send token + apiKey +
|
|
246
|
+
// Send token + apiKey + identifierId to backend — response returns a JWT used for all subsequent calls
|
|
246
247
|
// sdkToken is nil here so no Authorization header is injected on this call
|
|
247
|
-
let verifyPayload: [String: Any] = ["token": token, "api_key": key, "
|
|
248
|
-
post(endpoint: "/
|
|
248
|
+
let verifyPayload: [String: Any] = ["token": token, "api_key": key, "identifier_id": uid]
|
|
249
|
+
post(endpoint: "\(apiBasePath)/verify", payload: verifyPayload) { [weak self] result in
|
|
249
250
|
guard let self = self else { return }
|
|
250
251
|
switch result {
|
|
251
252
|
case .success(let (status, data)):
|
|
@@ -483,7 +484,7 @@ public class SpotnyBeaconScanner: NSObject {
|
|
|
483
484
|
if let exp = sdkTokenExpiry { keychainWrite(key: "SpotnySDK_jwtExpiry", value: String(exp.timeIntervalSince1970)) }
|
|
484
485
|
if let cred = sdkCredential { keychainWrite(key: "SpotnySDK_sdkCredential", value: cred) }
|
|
485
486
|
if let key = apiKey { keychainWrite(key: "SpotnySDK_apiKey", value: key) }
|
|
486
|
-
if let uid =
|
|
487
|
+
if let uid = identifierId { keychainWrite(key: "SpotnySDK_identifierId", value: uid) }
|
|
487
488
|
}
|
|
488
489
|
|
|
489
490
|
/// Refresh the JWT. Concurrent callers are queued and flushed together when the single
|
|
@@ -499,8 +500,8 @@ public class SpotnyBeaconScanner: NSObject {
|
|
|
499
500
|
return
|
|
500
501
|
}
|
|
501
502
|
jwtRefreshInProgress = true
|
|
502
|
-
let refreshPayload: [String: Any] = ["token": credential, "api_key": key, "
|
|
503
|
-
performPost(endpoint: "/
|
|
503
|
+
let refreshPayload: [String: Any] = ["token": credential, "api_key": key, "identifier_id": identifierId ?? ""]
|
|
504
|
+
performPost(endpoint: "\(apiBasePath)/verify", payload: refreshPayload) { [weak self] result in
|
|
504
505
|
guard let self = self else { return }
|
|
505
506
|
let flush: (Error?) -> Void = { err in
|
|
506
507
|
let queue = self.jwtRefreshQueue
|
|
@@ -542,7 +543,7 @@ public class SpotnyBeaconScanner: NSObject {
|
|
|
542
543
|
payload: [String: Any],
|
|
543
544
|
completion: @escaping (Result<(Int, Data), Error>) -> Void
|
|
544
545
|
) {
|
|
545
|
-
guard endpoint == "/
|
|
546
|
+
guard endpoint == "\(apiBasePath)/verify" || !isTokenExpired() else {
|
|
546
547
|
refreshJWT { [weak self] error in
|
|
547
548
|
if let error = error { completion(.failure(error)); return }
|
|
548
549
|
self?.performPost(endpoint: endpoint, payload: payload, completion: completion)
|
|
@@ -615,7 +616,7 @@ public class SpotnyBeaconScanner: NSObject {
|
|
|
615
616
|
|
|
616
617
|
let payload: [String: Any] = ["beacon_id": key]
|
|
617
618
|
|
|
618
|
-
post(endpoint: "/
|
|
619
|
+
post(endpoint: "\(apiBasePath)/distribute", payload: payload) { [weak self] result in
|
|
619
620
|
guard let self = self else { return }
|
|
620
621
|
defer { self.fetchInProgress[key] = false }
|
|
621
622
|
|
|
@@ -726,12 +727,12 @@ public class SpotnyBeaconScanner: NSObject {
|
|
|
726
727
|
|
|
727
728
|
private func sendProximity(eventType: String, key: String, distance: Double) {
|
|
728
729
|
sendTracking(eventType: eventType, key: key, distance: distance,
|
|
729
|
-
endpoint: "/
|
|
730
|
+
endpoint: "\(apiBasePath)/proximity")
|
|
730
731
|
}
|
|
731
732
|
|
|
732
733
|
private func sendImpression(key: String, distance: Double) {
|
|
733
734
|
sendTracking(eventType: "IMPRESSION_HEARTBEAT", key: key, distance: distance,
|
|
734
|
-
endpoint: "/
|
|
735
|
+
endpoint: "\(apiBasePath)/track")
|
|
735
736
|
}
|
|
736
737
|
|
|
737
738
|
// MARK: - State Cleanup
|
|
@@ -34,10 +34,10 @@ export type SpotnySdkConfig = {
|
|
|
34
34
|
*/
|
|
35
35
|
apiKey: string;
|
|
36
36
|
/**
|
|
37
|
-
*
|
|
37
|
+
* Unique identifier for the authenticated user (e.g. database UUID, hashed email).
|
|
38
38
|
* Embedded in the JWT so all tracking events are tied to this user. Required.
|
|
39
39
|
*/
|
|
40
|
-
|
|
40
|
+
identifierId: string;
|
|
41
41
|
/** Maximum BLE detection distance in metres (default: 8.0) */
|
|
42
42
|
maxDetectionDistance?: number;
|
|
43
43
|
/**
|
|
@@ -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;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,
|
|
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;;;OAGG;IACH,KAAK,EAAE,MAAM,CAAC;IACd;;;OAGG;IACH,MAAM,EAAE,MAAM,CAAC;IACf;;;OAGG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,8DAA8D;IAC9D,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B;;;OAGG;IACH,wBAAwB,CAAC,EAAE,MAAM,CAAC;CACnC,CAAC;AAOF,6BAA6B;AAC7B,wBAAgB,YAAY,IAAI,OAAO,CAAC,MAAM,CAAC,CAE9C;AAED,mDAAmD;AACnD,wBAAgB,WAAW,IAAI,OAAO,CAAC,MAAM,CAAC,CAE7C;AAED,uDAAuD;AACvD,wBAAgB,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,CAE7C;AAID;;GAEG;AACH,wBAAgB,UAAU,CAAC,MAAM,EAAE,eAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAEnE;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
package/src/index.tsx
CHANGED
|
@@ -44,10 +44,10 @@ export type SpotnySdkConfig = {
|
|
|
44
44
|
*/
|
|
45
45
|
apiKey: string;
|
|
46
46
|
/**
|
|
47
|
-
*
|
|
47
|
+
* Unique identifier for the authenticated user (e.g. database UUID, hashed email).
|
|
48
48
|
* Embedded in the JWT so all tracking events are tied to this user. Required.
|
|
49
49
|
*/
|
|
50
|
-
|
|
50
|
+
identifierId: string;
|
|
51
51
|
/** Maximum BLE detection distance in metres (default: 8.0) */
|
|
52
52
|
maxDetectionDistance?: number;
|
|
53
53
|
/**
|