@wayq/beekon-rn 0.0.6 → 0.0.7

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.
Files changed (46) hide show
  1. package/BeekonRn.podspec +1 -1
  2. package/CHANGELOG.md +24 -0
  3. package/android/build.gradle +3 -2
  4. package/android/src/main/java/in/wayq/beekonrn/BeekonRnModule.kt +51 -0
  5. package/ios/BeekonRn.mm +10 -0
  6. package/ios/BeekonRn.swift +87 -2
  7. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/BeekonKit +0 -0
  8. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.abi.json +1179 -28
  9. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.swiftdoc +0 -0
  10. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios.swiftinterface +34 -1
  11. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/BeekonKit +0 -0
  12. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.abi.json +1179 -28
  13. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.swiftdoc +0 -0
  14. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/arm64-apple-ios-simulator.swiftinterface +34 -1
  15. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.abi.json +1179 -28
  16. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.swiftdoc +0 -0
  17. package/ios/Frameworks/BeekonKit.xcframework/ios-arm64_x86_64-simulator/BeekonKit.framework/Modules/BeekonKit.swiftmodule/x86_64-apple-ios-simulator.swiftinterface +34 -1
  18. package/lib/module/NativeBeekonRn.js +7 -0
  19. package/lib/module/NativeBeekonRn.js.map +1 -1
  20. package/lib/module/beekon.js +35 -1
  21. package/lib/module/beekon.js.map +1 -1
  22. package/lib/module/index.js.map +1 -1
  23. package/lib/module/internal/mappers.js +48 -1
  24. package/lib/module/internal/mappers.js.map +1 -1
  25. package/lib/module/types/license.js +2 -0
  26. package/lib/module/types/license.js.map +1 -0
  27. package/lib/typescript/src/NativeBeekonRn.d.ts +36 -0
  28. package/lib/typescript/src/NativeBeekonRn.d.ts.map +1 -1
  29. package/lib/typescript/src/beekon.d.ts +15 -0
  30. package/lib/typescript/src/beekon.d.ts.map +1 -1
  31. package/lib/typescript/src/index.d.ts +1 -0
  32. package/lib/typescript/src/index.d.ts.map +1 -1
  33. package/lib/typescript/src/internal/mappers.d.ts +8 -1
  34. package/lib/typescript/src/internal/mappers.d.ts.map +1 -1
  35. package/lib/typescript/src/types/config.d.ts +13 -0
  36. package/lib/typescript/src/types/config.d.ts.map +1 -1
  37. package/lib/typescript/src/types/license.d.ts +50 -0
  38. package/lib/typescript/src/types/license.d.ts.map +1 -0
  39. package/package.json +6 -2
  40. package/scripts/fetch-beekonkit.sh +4 -4
  41. package/src/NativeBeekonRn.ts +38 -0
  42. package/src/beekon.ts +38 -0
  43. package/src/index.tsx +1 -0
  44. package/src/internal/mappers.ts +50 -0
  45. package/src/types/config.ts +13 -0
  46. package/src/types/license.ts +47 -0
package/BeekonRn.podspec CHANGED
@@ -11,7 +11,7 @@ Pod::Spec.new do |s|
11
11
  s.authors = package["author"]
12
12
 
13
13
  # iOS 17.0 floor reflects this wrapper's React Native baseline (RN 0.85), not
14
- # a BeekonKit constraint — BeekonKit 0.0.6 itself supports iOS 13+ (with
14
+ # a BeekonKit constraint — BeekonKit 0.0.7 itself supports iOS 13+ (with
15
15
  # 13–16 fallback paths). Kept at 17.0 to avoid any consumer regression; do not
16
16
  # lower below React Native's own minimum.
17
17
  s.platforms = { :ios => "17.0" }
package/CHANGELOG.md CHANGED
@@ -6,6 +6,30 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
  Beekon is pre-1.0 — releases may contain breaking changes.
8
8
 
9
+ ## [0.0.7]
10
+
11
+ Built against the native **0.0.7** API; requires native ≥ 0.0.7 at runtime.
12
+
13
+ ### Added
14
+
15
+ - **License surface** (`license-format-v1`) — a pure pass-through to the native
16
+ verifier; the binding performs no validation of its own.
17
+ - `BeekonConfig.licenseKey` — supply a license token (a `license-format-v1`
18
+ JWS). The highest-priority channel, overriding the Android manifest
19
+ (`in.wayq.beekon.license`) / iOS `Info.plist` (`BeekonLicenseKey`) value;
20
+ `undefined`/blank means unset. Safe to commit to source control (app-id- and
21
+ product-bound).
22
+ - `Beekon.licenseStatus()` (one-shot) and `Beekon.onLicenseStatus(cb)`
23
+ (replay-1 subscription) expose the current platform's status: the
24
+ discriminated `LicenseStatus` union (`notDetermined` / `licensed` /
25
+ `evaluation` / `expired` / `updateEntitlementLapsed` / `invalid`) plus
26
+ `LicenseInvalidReason`. Purely observational — no status ever blocks,
27
+ degrades, or delays the SDK; Android and iOS may legally diverge for the
28
+ same app.
29
+ - The binding identifies itself to the verifier as the `rn` product.
30
+ - Native pins bumped to `0.0.7` (Maven `io.github.wayqteam:beekon`, `BeekonKit`
31
+ xcframework).
32
+
9
33
  ## [0.0.6]
10
34
 
11
35
  Built against the native **0.0.6** API; requires native ≥ 0.0.6 at runtime.
@@ -76,8 +76,9 @@ dependencies {
76
76
  implementation "com.facebook.react:react-android"
77
77
  // Native Beekon SDK — published from beekon-android/ via Maven Central.
78
78
  // Pinned exact in v0.x to avoid surprise breakage; loosen to a range when
79
- // the SDK reaches v1 stability.
80
- implementation "io.github.wayqteam:beekon:0.0.6"
79
+ // the SDK reaches v1 stability. 0.0.7 is the release that ships the license
80
+ // API (setWrapperInfo / BeekonConfig.licenseKey / Beekon.licenseStatus).
81
+ implementation "io.github.wayqteam:beekon:0.0.7"
81
82
  // Kotlin coroutines — required for collecting Beekon's StateFlow/SharedFlow.
82
83
  // Beekon already depends on coroutines transitively, but declaring it here
83
84
  // makes the dependency intent explicit.
@@ -20,6 +20,7 @@ import `in`.wayq.beekon.BeekonException
20
20
  import `in`.wayq.beekon.BeekonGeofence
21
21
  import `in`.wayq.beekon.BeekonState
22
22
  import `in`.wayq.beekon.GeofenceEvent
23
+ import `in`.wayq.beekon.LicenseStatus
23
24
  import `in`.wayq.beekon.Location
24
25
  import `in`.wayq.beekon.LocationQuality
25
26
  import `in`.wayq.beekon.LocationTrigger
@@ -49,6 +50,11 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
49
50
  private val scope = CoroutineScope(SupervisorJob() + Dispatchers.Default)
50
51
 
51
52
  init {
53
+ // Identify this wrapper to the native verifier (license-format-v1 §11) before
54
+ // any configure() can run — a direct native call, deliberately not bridged to
55
+ // JS. The module is constructed before its first method dispatch, so this is
56
+ // always set first.
57
+ Beekon.setWrapperInfo("rn", WRAPPER_VERSION)
52
58
  // No Beekon.initialize() — the SDK auto-initializes via AndroidX Startup.
53
59
  scope.launch { Beekon.state.collect { emitOnState(stateToWire(it)) } }
54
60
  scope.launch { Beekon.locations.collect { emitOnLocation(locationToWire(it)) } }
@@ -57,6 +63,7 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
57
63
  }
58
64
  scope.launch { Beekon.syncStatus.collect { emitOnSyncStatus(syncStatusToWire(it)) } }
59
65
  scope.launch { Beekon.authChanges.collect { emitOnAuthTokens(tokenRefreshToWire(it)) } }
66
+ scope.launch { Beekon.licenseStatus.collect { emitOnLicenseStatus(licenseStatusToWire(it)) } }
60
67
  }
61
68
 
62
69
  // ---------------------------------------------------------------------------
@@ -216,6 +223,15 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
216
223
  }
217
224
  }
218
225
 
226
+ // ---------------------------------------------------------------------------
227
+ // License (observational only — never blocks; license-format-v1 §8)
228
+ // ---------------------------------------------------------------------------
229
+
230
+ override fun licenseStatus(promise: Promise) {
231
+ // StateFlow.value is the current, synchronously-readable status.
232
+ promise.resolve(licenseStatusToWire(Beekon.licenseStatus.value))
233
+ }
234
+
219
235
  override fun invalidate() {
220
236
  super.invalidate()
221
237
  scope.cancel()
@@ -249,6 +265,9 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
249
265
  detectActivity = map.getBoolean("detectActivity"),
250
266
  sync = sync,
251
267
  notification = notification ?: NotificationConfig(),
268
+ // Passed through verbatim; absent/null means unset — the SDK falls through
269
+ // to the manifest meta-data, then evaluation (license-format-v1 §9).
270
+ licenseKey = optString(map, "licenseKey"),
252
271
  )
253
272
  }
254
273
 
@@ -438,6 +457,33 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
438
457
  return m
439
458
  }
440
459
 
460
+ // Reads the SDK's wire-stable names (no validation here). `tier`/`entitlements`
461
+ // populate only for Licensed; `reason` only for Invalid.
462
+ private fun licenseStatusToWire(s: LicenseStatus): WritableMap {
463
+ val m = Arguments.createMap()
464
+ m.putString("status", s.wireName)
465
+ when (s) {
466
+ is LicenseStatus.Licensed -> {
467
+ m.putString("tier", s.tier)
468
+ val arr: WritableArray = Arguments.createArray()
469
+ for (e in s.entitlements) arr.pushString(e)
470
+ m.putArray("entitlements", arr)
471
+ m.putNull("reason")
472
+ }
473
+ is LicenseStatus.Invalid -> {
474
+ m.putNull("tier")
475
+ m.putArray("entitlements", Arguments.createArray())
476
+ m.putString("reason", s.reason.wireName)
477
+ }
478
+ else -> {
479
+ m.putNull("tier")
480
+ m.putArray("entitlements", Arguments.createArray())
481
+ m.putNull("reason")
482
+ }
483
+ }
484
+ return m
485
+ }
486
+
441
487
  private fun putNullableDouble(map: WritableMap, key: String, value: Double?) {
442
488
  if (value == null) map.putNull(key) else map.putDouble(key, value)
443
489
  }
@@ -530,5 +576,10 @@ class BeekonRnModule(reactContext: ReactApplicationContext) :
530
576
 
531
577
  companion object {
532
578
  const val NAME = NativeBeekonRnSpec.NAME
579
+
580
+ // Reported to the native verifier via setWrapperInfo (diagnostics only — the
581
+ // verifier consumes only the product). Keep in sync with package.json
582
+ // "version" on release.
583
+ private const val WRAPPER_VERSION = "0.0.7"
533
584
  }
534
585
  }
package/ios/BeekonRn.mm CHANGED
@@ -32,6 +32,9 @@
32
32
  }
33
33
  onAuthTokens:^(NSDictionary *_Nonnull t) {
34
34
  [weakSelf emitOnAuthTokens:t];
35
+ }
36
+ onLicenseStatus:^(NSDictionary *_Nonnull ls) {
37
+ [weakSelf emitOnLicenseStatus:ls];
35
38
  }];
36
39
  }
37
40
  return self;
@@ -137,6 +140,13 @@
137
140
  [_impl listGeofencesWithResolver:resolve rejecter:reject];
138
141
  }
139
142
 
143
+ // MARK: - License
144
+
145
+ - (void)licenseStatus:(RCTPromiseResolveBlock)resolve
146
+ reject:(RCTPromiseRejectBlock)reject {
147
+ [_impl licenseStatusWithResolver:resolve rejecter:reject];
148
+ }
149
+
140
150
  - (std::shared_ptr<facebook::react::TurboModule>)getTurboModule:
141
151
  (const facebook::react::ObjCTurboModule::InitParams &)params {
142
152
  return std::make_shared<facebook::react::NativeBeekonRnSpecJSI>(params);
@@ -23,25 +23,38 @@ import BeekonKit
23
23
  private let onGeofenceEventCb: (NSDictionary) -> Void
24
24
  private let onSyncStatusCb: (NSDictionary) -> Void
25
25
  private let onAuthTokensCb: (NSDictionary) -> Void
26
+ private let onLicenseStatusCb: (NSDictionary) -> Void
26
27
 
27
28
  private var stateTask: Task<Void, Never>?
28
29
  private var locationsTask: Task<Void, Never>?
29
30
  private var geofenceEventsTask: Task<Void, Never>?
30
31
  private var syncStatusTask: Task<Void, Never>?
31
32
  private var authTokensTask: Task<Void, Never>?
33
+ private var licenseStatusTask: Task<Void, Never>?
34
+
35
+ // Reported to the native verifier via setWrapperInfo (diagnostics only — the
36
+ // verifier consumes only the product). Keep in sync with package.json
37
+ // "version" on release.
38
+ private static let wrapperVersion = "0.0.7"
32
39
 
33
40
  @objc public init(
34
41
  onState: @escaping (NSDictionary) -> Void,
35
42
  onLocation: @escaping (NSDictionary) -> Void,
36
43
  onGeofenceEvent: @escaping (NSDictionary) -> Void,
37
44
  onSyncStatus: @escaping (NSDictionary) -> Void,
38
- onAuthTokens: @escaping (NSDictionary) -> Void
45
+ onAuthTokens: @escaping (NSDictionary) -> Void,
46
+ onLicenseStatus: @escaping (NSDictionary) -> Void
39
47
  ) {
48
+ // Identify this wrapper to the native verifier (license-format-v1 §11) before
49
+ // any configure() can run — a direct native call (nonisolated static),
50
+ // deliberately not bridged to JS.
51
+ Beekon.setWrapperInfo(product: "rn", version: BeekonRnImpl.wrapperVersion)
40
52
  self.onStateCb = onState
41
53
  self.onLocationCb = onLocation
42
54
  self.onGeofenceEventCb = onGeofenceEvent
43
55
  self.onSyncStatusCb = onSyncStatus
44
56
  self.onAuthTokensCb = onAuthTokens
57
+ self.onLicenseStatusCb = onLicenseStatus
45
58
  super.init()
46
59
  self.stateTask = Task { [weak self] in
47
60
  guard let self = self else { return }
@@ -73,6 +86,12 @@ import BeekonKit
73
86
  self.onAuthTokensCb(self.authTokensToWire(tokens))
74
87
  }
75
88
  }
89
+ self.licenseStatusTask = Task { [weak self] in
90
+ guard let self = self else { return }
91
+ for await status in await Beekon.shared.licenseStatusUpdates {
92
+ self.onLicenseStatusCb(self.licenseStatusToWire(status))
93
+ }
94
+ }
76
95
  }
77
96
 
78
97
  @objc public func invalidate() {
@@ -81,11 +100,13 @@ import BeekonKit
81
100
  geofenceEventsTask?.cancel()
82
101
  syncStatusTask?.cancel()
83
102
  authTokensTask?.cancel()
103
+ licenseStatusTask?.cancel()
84
104
  stateTask = nil
85
105
  locationsTask = nil
86
106
  geofenceEventsTask = nil
87
107
  syncStatusTask = nil
88
108
  authTokensTask = nil
109
+ licenseStatusTask = nil
89
110
  }
90
111
 
91
112
  /// Register Beekon's background-refresh task and install cold-launch hooks.
@@ -288,6 +309,19 @@ import BeekonKit
288
309
  }
289
310
  }
290
311
 
312
+ // MARK: - License (observational only — never blocks; license-format-v1 §8)
313
+
314
+ @objc public func licenseStatusWithResolver(
315
+ _ resolve: @escaping @Sendable (Any?) -> Void,
316
+ rejecter _: @escaping @Sendable (String?, String?, Error?) -> Void
317
+ ) {
318
+ Task { [weak self] in
319
+ guard let self = self else { return }
320
+ // `licenseStatus` is an actor-isolated property — read it with `await`.
321
+ resolve(self.licenseStatusToWire(await Beekon.shared.licenseStatus))
322
+ }
323
+ }
324
+
291
325
  // MARK: - Mappers: wire (NSDictionary/NSArray) → Beekon
292
326
 
293
327
  private func wireToConfig(_ d: NSDictionary) -> BeekonConfig {
@@ -326,7 +360,10 @@ import BeekonKit
326
360
  whenStationary: stationaryModeFromWire(d["whenStationary"] as? String),
327
361
  stationaryRadiusMeters: stationaryRadius,
328
362
  detectActivity: detectActivity,
329
- sync: sync
363
+ sync: sync,
364
+ // Passed through verbatim; nil/blank means unset — the SDK falls through to
365
+ // the Info.plist value, then evaluation (license-format-v1 §9).
366
+ licenseKey: d["licenseKey"] as? String
330
367
  )
331
368
  }
332
369
 
@@ -473,6 +510,54 @@ import BeekonKit
473
510
  return d
474
511
  }
475
512
 
513
+ private func licenseStatusToWire(_ s: LicenseStatus) -> NSDictionary {
514
+ // NSDictionary literals can't carry `nil`; optionals collapse to `NSNull`,
515
+ // which the Codegen layer translates back to `null` on the JS side. iOS has
516
+ // no `.wireName`, so the wire-stable strings are written literally here (as
517
+ // with stateToWire / syncStatusToWire). No validation — the SDK already
518
+ // decided the status.
519
+ let d = NSMutableDictionary()
520
+ switch s {
521
+ case let .licensed(tier, entitlements):
522
+ d["status"] = "licensed"
523
+ d["tier"] = tier
524
+ d["entitlements"] = entitlements
525
+ d["reason"] = NSNull()
526
+ case let .invalid(reason):
527
+ d["status"] = "invalid"
528
+ d["tier"] = NSNull()
529
+ d["entitlements"] = [String]()
530
+ d["reason"] = reason.rawValue
531
+ case .evaluation:
532
+ d["status"] = "evaluation"
533
+ d["tier"] = NSNull()
534
+ d["entitlements"] = [String]()
535
+ d["reason"] = NSNull()
536
+ case .expired:
537
+ d["status"] = "expired"
538
+ d["tier"] = NSNull()
539
+ d["entitlements"] = [String]()
540
+ d["reason"] = NSNull()
541
+ case .updateEntitlementLapsed:
542
+ d["status"] = "updateEntitlementLapsed"
543
+ d["tier"] = NSNull()
544
+ d["entitlements"] = [String]()
545
+ d["reason"] = NSNull()
546
+ case .notDetermined:
547
+ d["status"] = "notDetermined"
548
+ d["tier"] = NSNull()
549
+ d["entitlements"] = [String]()
550
+ d["reason"] = NSNull()
551
+ // BeekonKit enums are non-frozen (library-evolution binary); handle unknowns.
552
+ @unknown default:
553
+ d["status"] = "notDetermined"
554
+ d["tier"] = NSNull()
555
+ d["entitlements"] = [String]()
556
+ d["reason"] = NSNull()
557
+ }
558
+ return d
559
+ }
560
+
476
561
  // MARK: - Enum mappers
477
562
 
478
563
  private func accuracyModeFromWire(_ s: String?) -> AccuracyMode {