react-native-audio-browser 0.2.0-next.1 → 0.2.0-next.11

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 (290) hide show
  1. package/README.md +22 -18
  2. package/android/build.gradle +13 -10
  3. package/android/gradle.properties +2 -2
  4. package/android/src/main/AndroidManifest.xml +3 -1
  5. package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +76 -21
  6. package/android/src/main/java/com/audiobrowser/AudioBrowserLifecycleModule.kt +38 -0
  7. package/android/src/main/java/com/audiobrowser/AudioBrowserPackage.kt +18 -2
  8. package/android/src/main/java/com/audiobrowser/ServiceBinding.kt +48 -0
  9. package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +1 -2
  10. package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +1 -2
  11. package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +6 -7
  12. package/android/src/main/java/com/audiobrowser/http/HttpClient.kt +20 -3
  13. package/android/src/main/java/com/audiobrowser/model/PlayerUpdateOptions.kt +11 -11
  14. package/android/src/main/java/com/audiobrowser/player/CapabilityControls.kt +111 -58
  15. package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +9 -5
  16. package/android/src/main/java/com/audiobrowser/player/MediaSessionCommandManager.kt +218 -252
  17. package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +0 -1
  18. package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +2 -4
  19. package/android/src/main/java/com/audiobrowser/player/Player.kt +30 -8
  20. package/android/src/main/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicy.kt +2 -1
  21. package/android/src/main/java/com/audiobrowser/player/TransformingDataSource.kt +2 -1
  22. package/android/src/main/java/com/audiobrowser/tls/AiaCertChaser.kt +67 -11
  23. package/android/src/main/java/com/audiobrowser/tls/AiaChasingExtendedTrustManager.kt +168 -0
  24. package/android/src/main/java/com/audiobrowser/tls/AiaChasingTrustManager.kt +58 -14
  25. package/android/src/main/java/com/audiobrowser/tls/AiaTls.kt +35 -7
  26. package/android/src/main/java/com/audiobrowser/tls/CachingCertificateFetcher.kt +278 -59
  27. package/android/src/main/java/com/audiobrowser/util/ArtworkVariant.kt +7 -9
  28. package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +8 -7
  29. package/android/src/test/java/com/audiobrowser/ServiceBindingTest.kt +87 -0
  30. package/android/src/test/java/com/audiobrowser/TestFixtures.kt +52 -1
  31. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerLayerResolutionTest.kt +6 -0
  32. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +167 -8
  33. package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +2 -1
  34. package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +2 -4
  35. package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +100 -56
  36. package/android/src/test/java/com/audiobrowser/player/MediaSessionSlotMappingTest.kt +45 -0
  37. package/android/src/test/java/com/audiobrowser/player/PlaybackErrorClassifierTest.kt +3 -4
  38. package/android/src/test/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicyTest.kt +3 -3
  39. package/android/src/test/java/com/audiobrowser/tls/AiaCertChaserTest.kt +197 -7
  40. package/android/src/test/java/com/audiobrowser/tls/AiaChasingTrustManagerTest.kt +325 -4
  41. package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherCallSiteTest.kt +322 -0
  42. package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherTest.kt +83 -0
  43. package/ios/Browser/BrowserManager.swift +2 -27
  44. package/ios/Browser/SearchDrillIn.swift +1 -1
  45. package/ios/CarPlay/RNABMediaAddHandler.swift +6 -6
  46. package/ios/CarPlay/RNABMediaAffinityHandler.swift +2 -2
  47. package/ios/CarPlay/RNABMediaIntentHandler.swift +16 -16
  48. package/ios/HybridAudioBrowser.swift +87 -56
  49. package/ios/Model/NitroTypeStubs.swift +18 -2
  50. package/ios/Model/RemoteCommand.swift +18 -0
  51. package/ios/Model/TrackPlayerError.swift +2 -2
  52. package/ios/Option/SessionCategories.swift +3 -2
  53. package/ios/Player/MediaIntentCriteria.swift +4 -4
  54. package/ios/Player/MediaLoader.swift +3 -1
  55. package/ios/Player/PlaybackCoordinator.swift +4 -1
  56. package/ios/Player/PlaybackErrorHandler.swift +4 -4
  57. package/ios/Player/QueueManager.swift +10 -3
  58. package/ios/Player/RetryManager.swift +79 -18
  59. package/ios/Player/ShuffleOrder.swift +10 -0
  60. package/ios/Player/SleepTimerManager.swift +43 -15
  61. package/ios/RemoteCommand/RemoteCommandCallbacks.swift +47 -0
  62. package/ios/RemoteCommand/RemoteCommandController.swift +9 -6
  63. package/ios/Tests/LRUCacheTests.swift +111 -0
  64. package/ios/Tests/LoadSeekCoordinatorTests.swift +3 -1
  65. package/ios/Tests/MediaIntentCriteriaTests.swift +2 -2
  66. package/ios/Tests/MediaLoaderTests.swift +10 -13
  67. package/ios/Tests/PlaybackCoordinatorTests.swift +10 -7
  68. package/ios/Tests/PlaybackErrorHandlerTests.swift +3 -1
  69. package/ios/Tests/PlayerTimeObserverTests.swift +37 -0
  70. package/ios/Tests/QueueManagerTests.swift +50 -4
  71. package/ios/Tests/RemoteCommandControllerTests.swift +156 -0
  72. package/ios/Tests/RemoteCommandTests.swift +67 -0
  73. package/ios/Tests/RetryManagerTests.swift +89 -0
  74. package/ios/Tests/SectionScopeTests.swift +2 -2
  75. package/ios/Tests/SleepTimerManagerTests.swift +22 -19
  76. package/ios/Tests/Support/ManualSleepTimerScheduler.swift +47 -0
  77. package/ios/Tests/Support/TestTypes.swift +1 -1
  78. package/ios/Tests/TabBarEntriesTests.swift +7 -7
  79. package/ios/TrackPlayer.swift +6 -1
  80. package/ios/TrackPlayerCallbacks.swift +5 -38
  81. package/ios/Util/LRUCache.swift +4 -1
  82. package/lib/commonjs/AudioBrowser.js +0 -11
  83. package/lib/commonjs/AudioBrowser.js.map +1 -1
  84. package/lib/commonjs/CLAUDE.md +52 -0
  85. package/lib/commonjs/features/browser.js +1 -1
  86. package/lib/commonjs/features/browser.js.map +1 -1
  87. package/lib/commonjs/features/carConnection.js +1 -1
  88. package/lib/commonjs/features/equalizer.js +1 -1
  89. package/lib/commonjs/features/errors.js +3 -3
  90. package/lib/commonjs/features/favorites.js +1 -1
  91. package/lib/commonjs/features/gate.js +16 -1
  92. package/lib/commonjs/features/gate.js.map +1 -1
  93. package/lib/commonjs/features/metadata.js +20 -3
  94. package/lib/commonjs/features/metadata.js.map +1 -1
  95. package/lib/commonjs/features/network.js +1 -1
  96. package/lib/commonjs/features/nowPlaying.js +1 -1
  97. package/lib/commonjs/features/output.js +1 -1
  98. package/lib/commonjs/features/playback/playWhenReady.js +1 -1
  99. package/lib/commonjs/features/playback/playing.js +1 -1
  100. package/lib/commonjs/features/playback/progress.js +1 -1
  101. package/lib/commonjs/features/playback/state.js +1 -1
  102. package/lib/commonjs/features/playback/trackPlaybackTime.js +0 -6
  103. package/lib/commonjs/features/playback/trackPlaybackTime.js.map +1 -1
  104. package/lib/commonjs/features/playback/volume.js +1 -1
  105. package/lib/commonjs/features/player/options.js +48 -34
  106. package/lib/commonjs/features/player/options.js.map +1 -1
  107. package/lib/commonjs/features/player/setup.js +15 -8
  108. package/lib/commonjs/features/player/setup.js.map +1 -1
  109. package/lib/commonjs/features/player/validateOptions.js +21 -0
  110. package/lib/commonjs/features/player/validateOptions.js.map +1 -0
  111. package/lib/commonjs/features/queue/activeTrack.js +1 -1
  112. package/lib/commonjs/features/queue/queue.js +2 -2
  113. package/lib/commonjs/features/queue/repeatMode.js +1 -1
  114. package/lib/commonjs/features/queue/shuffle.js +1 -1
  115. package/lib/commonjs/features/remoteControls.js +13 -92
  116. package/lib/commonjs/features/remoteControls.js.map +1 -1
  117. package/lib/commonjs/features/sleepTimer.js +13 -1
  118. package/lib/commonjs/features/sleepTimer.js.map +1 -1
  119. package/lib/commonjs/test-utils/reactNativeStub.js +65 -0
  120. package/lib/commonjs/test-utils/reactNativeStub.js.map +1 -0
  121. package/lib/commonjs/utils/LazyNativeEmitter.js +8 -5
  122. package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -1
  123. package/lib/commonjs/web/NativeAudioBrowser.js +1 -1
  124. package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
  125. package/lib/commonjs/web/browser/BrowserManager.js +1 -1
  126. package/lib/module/AudioBrowser.js +1 -1
  127. package/lib/module/AudioBrowser.js.map +1 -1
  128. package/lib/module/CLAUDE.md +52 -0
  129. package/lib/module/features/browser.js +1 -1
  130. package/lib/module/features/browser.js.map +1 -1
  131. package/lib/module/features/carConnection.js +1 -1
  132. package/lib/module/features/equalizer.js +1 -1
  133. package/lib/module/features/errors.js +3 -3
  134. package/lib/module/features/favorites.js +1 -1
  135. package/lib/module/features/gate.js +16 -1
  136. package/lib/module/features/gate.js.map +1 -1
  137. package/lib/module/features/metadata.js +20 -3
  138. package/lib/module/features/metadata.js.map +1 -1
  139. package/lib/module/features/network.js +1 -1
  140. package/lib/module/features/nowPlaying.js +1 -1
  141. package/lib/module/features/output.js +1 -1
  142. package/lib/module/features/playback/playWhenReady.js +1 -1
  143. package/lib/module/features/playback/playing.js +1 -1
  144. package/lib/module/features/playback/progress.js +1 -1
  145. package/lib/module/features/playback/state.js +1 -1
  146. package/lib/module/features/playback/trackPlaybackTime.js +0 -5
  147. package/lib/module/features/playback/trackPlaybackTime.js.map +1 -1
  148. package/lib/module/features/playback/volume.js +1 -1
  149. package/lib/module/features/player/options.js +47 -32
  150. package/lib/module/features/player/options.js.map +1 -1
  151. package/lib/module/features/player/setup.js +14 -7
  152. package/lib/module/features/player/setup.js.map +1 -1
  153. package/lib/module/features/player/validateOptions.js +17 -0
  154. package/lib/module/features/player/validateOptions.js.map +1 -0
  155. package/lib/module/features/queue/activeTrack.js +1 -1
  156. package/lib/module/features/queue/queue.js +2 -2
  157. package/lib/module/features/queue/repeatMode.js +1 -1
  158. package/lib/module/features/queue/shuffle.js +1 -1
  159. package/lib/module/features/remoteControls.js +13 -92
  160. package/lib/module/features/remoteControls.js.map +1 -1
  161. package/lib/module/features/sleepTimer.js +13 -1
  162. package/lib/module/features/sleepTimer.js.map +1 -1
  163. package/lib/module/test-utils/reactNativeStub.js +58 -0
  164. package/lib/module/test-utils/reactNativeStub.js.map +1 -0
  165. package/lib/module/utils/LazyNativeEmitter.js +8 -5
  166. package/lib/module/utils/LazyNativeEmitter.js.map +1 -1
  167. package/lib/module/web/NativeAudioBrowser.js +1 -1
  168. package/lib/module/web/NativeAudioBrowser.js.map +1 -1
  169. package/lib/module/web/browser/BrowserManager.js +1 -1
  170. package/lib/typescript/src/AudioBrowser.d.ts +0 -1
  171. package/lib/typescript/src/AudioBrowser.d.ts.map +1 -1
  172. package/lib/typescript/src/features/carConnection.d.ts +1 -1
  173. package/lib/typescript/src/features/equalizer.d.ts +1 -1
  174. package/lib/typescript/src/features/errors.d.ts +3 -3
  175. package/lib/typescript/src/features/favorites.d.ts +1 -1
  176. package/lib/typescript/src/features/gate.d.ts +18 -2
  177. package/lib/typescript/src/features/gate.d.ts.map +1 -1
  178. package/lib/typescript/src/features/metadata.d.ts +20 -3
  179. package/lib/typescript/src/features/metadata.d.ts.map +1 -1
  180. package/lib/typescript/src/features/network.d.ts +1 -1
  181. package/lib/typescript/src/features/nowPlaying.d.ts +1 -1
  182. package/lib/typescript/src/features/output.d.ts +1 -1
  183. package/lib/typescript/src/features/playback/playWhenReady.d.ts +1 -1
  184. package/lib/typescript/src/features/playback/playing.d.ts +1 -1
  185. package/lib/typescript/src/features/playback/progress.d.ts +1 -1
  186. package/lib/typescript/src/features/playback/state.d.ts +1 -1
  187. package/lib/typescript/src/features/playback/volume.d.ts +1 -1
  188. package/lib/typescript/src/features/player/options.d.ts +87 -37
  189. package/lib/typescript/src/features/player/options.d.ts.map +1 -1
  190. package/lib/typescript/src/features/player/setup.d.ts +14 -4
  191. package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
  192. package/lib/typescript/src/features/player/validateOptions.d.ts +9 -0
  193. package/lib/typescript/src/features/player/validateOptions.d.ts.map +1 -0
  194. package/lib/typescript/src/features/queue/activeTrack.d.ts +1 -1
  195. package/lib/typescript/src/features/queue/queue.d.ts +2 -2
  196. package/lib/typescript/src/features/queue/repeatMode.d.ts +1 -1
  197. package/lib/typescript/src/features/queue/shuffle.d.ts +1 -1
  198. package/lib/typescript/src/features/remoteControls.d.ts +23 -22
  199. package/lib/typescript/src/features/remoteControls.d.ts.map +1 -1
  200. package/lib/typescript/src/features/sleepTimer.d.ts +1 -1
  201. package/lib/typescript/src/features/sleepTimer.d.ts.map +1 -1
  202. package/lib/typescript/src/test-utils/reactNativeStub.d.ts +36 -0
  203. package/lib/typescript/src/test-utils/reactNativeStub.d.ts.map +1 -0
  204. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +8 -4
  205. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -1
  206. package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +1 -1
  207. package/nitrogen/generated/android/c++/JAndroidOptions.hpp +10 -10
  208. package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +5 -5
  209. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +11 -11
  210. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.hpp +1 -1
  211. package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +5 -5
  212. package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +5 -5
  213. package/nitrogen/generated/android/c++/JNitroAndroidUpdateOptions.hpp +10 -10
  214. package/nitrogen/generated/android/c++/JOptions.hpp +5 -5
  215. package/nitrogen/generated/android/c++/{JNotificationButton.hpp → JRemoteButton.hpp} +19 -19
  216. package/nitrogen/generated/android/c++/JRemoteButtonLayout.hpp +86 -0
  217. package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.cpp +26 -0
  218. package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.hpp +75 -0
  219. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidOptions.kt +3 -3
  220. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HybridAudioBrowserSpec.kt +1 -1
  221. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroAndroidUpdateOptions.kt +3 -3
  222. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{NotificationButton.kt → RemoteButton.kt} +3 -3
  223. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteButtonLayout.kt +44 -0
  224. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Variant_NullType_NotificationButtonLayout.kt → Variant_NullType_RemoteButtonLayout.kt} +9 -9
  225. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +36 -51
  226. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +6 -6
  227. package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +8 -8
  228. package/nitrogen/generated/ios/swift/AndroidOptions.swift +12 -12
  229. package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec.swift +1 -1
  230. package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec_cxx.swift +2 -2
  231. package/nitrogen/generated/ios/swift/NitroAndroidUpdateOptions.swift +12 -12
  232. package/nitrogen/generated/ios/swift/{NotificationButton.swift → RemoteButton.swift} +6 -6
  233. package/nitrogen/generated/ios/swift/RemoteButtonLayout.swift +57 -0
  234. package/nitrogen/generated/ios/swift/{Variant_NullType_NotificationButtonLayout.swift → Variant_NullType_RemoteButtonLayout.swift} +3 -3
  235. package/nitrogen/generated/shared/c++/AndroidOptions.hpp +8 -8
  236. package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.cpp +1 -1
  237. package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.hpp +1 -1
  238. package/nitrogen/generated/shared/c++/NitroAndroidUpdateOptions.hpp +8 -8
  239. package/nitrogen/generated/shared/c++/{NotificationButton.hpp → RemoteButton.hpp} +19 -19
  240. package/nitrogen/generated/shared/c++/RemoteButtonLayout.hpp +94 -0
  241. package/package.json +12 -4
  242. package/src/AudioBrowser.ts +1 -1
  243. package/src/CLAUDE.md +52 -0
  244. package/src/features/battery.test.ts +79 -0
  245. package/src/features/browser.ts +1 -1
  246. package/src/features/carConnection.ts +1 -1
  247. package/src/features/equalizer.ts +1 -1
  248. package/src/features/errors.ts +3 -3
  249. package/src/features/favorites.ts +1 -1
  250. package/src/features/gate.ts +16 -1
  251. package/src/features/hook-wiring.test.ts +254 -0
  252. package/src/features/metadata.ts +20 -3
  253. package/src/features/network.ts +1 -1
  254. package/src/features/nowPlaying.ts +1 -1
  255. package/src/features/output.ts +1 -1
  256. package/src/features/playback/playWhenReady.ts +1 -1
  257. package/src/features/playback/playing.ts +1 -1
  258. package/src/features/playback/progress.test.ts +169 -0
  259. package/src/features/playback/progress.ts +1 -1
  260. package/src/features/playback/state.ts +1 -1
  261. package/src/features/playback/trackPlaybackTime.test.ts +16 -6
  262. package/src/features/playback/trackPlaybackTime.ts +0 -5
  263. package/src/features/playback/volume.ts +1 -1
  264. package/src/features/player/options.ts +99 -57
  265. package/src/features/player/setup.test.ts +12 -4
  266. package/src/features/player/setup.ts +19 -9
  267. package/src/features/player/validateOptions.ts +19 -0
  268. package/src/features/queue/activeTrack.ts +1 -1
  269. package/src/features/queue/queue.ts +2 -2
  270. package/src/features/queue/repeatMode.ts +1 -1
  271. package/src/features/queue/shuffle.ts +1 -1
  272. package/src/features/remoteControls.ts +13 -92
  273. package/src/features/sleepTimer.test.ts +172 -0
  274. package/src/features/sleepTimer.ts +9 -1
  275. package/src/nitro-stub-drift.test.ts +237 -0
  276. package/src/public-surface.test.ts +107 -0
  277. package/src/specs/audio-browser.nitro.ts +1 -1
  278. package/src/test-utils/reactNativeStub.ts +60 -0
  279. package/src/utils/LazyNativeEmitter.ts +9 -6
  280. package/src/utils/useDebug.test.ts +182 -0
  281. package/src/utils/useNativeUpdatedValue.test.ts +103 -0
  282. package/src/web/NativeAudioBrowser.ts +1 -1
  283. package/src/web/browser/BrowserManager.ts +1 -1
  284. package/ios/Model/MediaURL.swift +0 -67
  285. package/nitrogen/generated/android/c++/JNotificationButtonLayout.hpp +0 -94
  286. package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.cpp +0 -26
  287. package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.hpp +0 -75
  288. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButtonLayout.kt +0 -50
  289. package/nitrogen/generated/ios/swift/NotificationButtonLayout.swift +0 -92
  290. package/nitrogen/generated/shared/c++/NotificationButtonLayout.hpp +0 -102
@@ -1,5 +1,5 @@
1
1
  ///
2
- /// NotificationButton.hpp
2
+ /// RemoteButton.hpp
3
3
  /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
4
  /// https://github.com/mrousavy/nitro
5
5
  /// Copyright © Marc Rousavy @ Margelo
@@ -26,9 +26,9 @@
26
26
  namespace margelo::nitro::audiobrowser {
27
27
 
28
28
  /**
29
- * An enum which can be represented as a JavaScript union (NotificationButton).
29
+ * An enum which can be represented as a JavaScript union (RemoteButton).
30
30
  */
31
- enum class NotificationButton {
31
+ enum class RemoteButton {
32
32
  SKIP_TO_PREVIOUS SWIFT_NAME(skipToPrevious) = 0,
33
33
  SKIP_TO_NEXT SWIFT_NAME(skipToNext) = 1,
34
34
  JUMP_BACKWARD SWIFT_NAME(jumpBackward) = 2,
@@ -40,30 +40,30 @@ namespace margelo::nitro::audiobrowser {
40
40
 
41
41
  namespace margelo::nitro {
42
42
 
43
- // C++ NotificationButton <> JS NotificationButton (union)
43
+ // C++ RemoteButton <> JS RemoteButton (union)
44
44
  template <>
45
- struct JSIConverter<margelo::nitro::audiobrowser::NotificationButton> final {
46
- static inline margelo::nitro::audiobrowser::NotificationButton fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
45
+ struct JSIConverter<margelo::nitro::audiobrowser::RemoteButton> final {
46
+ static inline margelo::nitro::audiobrowser::RemoteButton fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
47
47
  std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, arg);
48
48
  switch (hashString(unionValue.c_str(), unionValue.size())) {
49
- case hashString("skip-to-previous"): return margelo::nitro::audiobrowser::NotificationButton::SKIP_TO_PREVIOUS;
50
- case hashString("skip-to-next"): return margelo::nitro::audiobrowser::NotificationButton::SKIP_TO_NEXT;
51
- case hashString("jump-backward"): return margelo::nitro::audiobrowser::NotificationButton::JUMP_BACKWARD;
52
- case hashString("jump-forward"): return margelo::nitro::audiobrowser::NotificationButton::JUMP_FORWARD;
53
- case hashString("favorite"): return margelo::nitro::audiobrowser::NotificationButton::FAVORITE;
49
+ case hashString("skip-to-previous"): return margelo::nitro::audiobrowser::RemoteButton::SKIP_TO_PREVIOUS;
50
+ case hashString("skip-to-next"): return margelo::nitro::audiobrowser::RemoteButton::SKIP_TO_NEXT;
51
+ case hashString("jump-backward"): return margelo::nitro::audiobrowser::RemoteButton::JUMP_BACKWARD;
52
+ case hashString("jump-forward"): return margelo::nitro::audiobrowser::RemoteButton::JUMP_FORWARD;
53
+ case hashString("favorite"): return margelo::nitro::audiobrowser::RemoteButton::FAVORITE;
54
54
  default: [[unlikely]]
55
- throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum NotificationButton - invalid value!");
55
+ throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum RemoteButton - invalid value!");
56
56
  }
57
57
  }
58
- static inline jsi::Value toJSI(jsi::Runtime& runtime, margelo::nitro::audiobrowser::NotificationButton arg) {
58
+ static inline jsi::Value toJSI(jsi::Runtime& runtime, margelo::nitro::audiobrowser::RemoteButton arg) {
59
59
  switch (arg) {
60
- case margelo::nitro::audiobrowser::NotificationButton::SKIP_TO_PREVIOUS: return JSIConverter<std::string>::toJSI(runtime, "skip-to-previous");
61
- case margelo::nitro::audiobrowser::NotificationButton::SKIP_TO_NEXT: return JSIConverter<std::string>::toJSI(runtime, "skip-to-next");
62
- case margelo::nitro::audiobrowser::NotificationButton::JUMP_BACKWARD: return JSIConverter<std::string>::toJSI(runtime, "jump-backward");
63
- case margelo::nitro::audiobrowser::NotificationButton::JUMP_FORWARD: return JSIConverter<std::string>::toJSI(runtime, "jump-forward");
64
- case margelo::nitro::audiobrowser::NotificationButton::FAVORITE: return JSIConverter<std::string>::toJSI(runtime, "favorite");
60
+ case margelo::nitro::audiobrowser::RemoteButton::SKIP_TO_PREVIOUS: return JSIConverter<std::string>::toJSI(runtime, "skip-to-previous");
61
+ case margelo::nitro::audiobrowser::RemoteButton::SKIP_TO_NEXT: return JSIConverter<std::string>::toJSI(runtime, "skip-to-next");
62
+ case margelo::nitro::audiobrowser::RemoteButton::JUMP_BACKWARD: return JSIConverter<std::string>::toJSI(runtime, "jump-backward");
63
+ case margelo::nitro::audiobrowser::RemoteButton::JUMP_FORWARD: return JSIConverter<std::string>::toJSI(runtime, "jump-forward");
64
+ case margelo::nitro::audiobrowser::RemoteButton::FAVORITE: return JSIConverter<std::string>::toJSI(runtime, "favorite");
65
65
  default: [[unlikely]]
66
- throw std::invalid_argument("Cannot convert NotificationButton to JS - invalid value: "
66
+ throw std::invalid_argument("Cannot convert RemoteButton to JS - invalid value: "
67
67
  + std::to_string(static_cast<int>(arg)) + "!");
68
68
  }
69
69
  }
@@ -0,0 +1,94 @@
1
+ ///
2
+ /// RemoteButtonLayout.hpp
3
+ /// This file was generated by nitrogen. DO NOT MODIFY THIS FILE.
4
+ /// https://github.com/mrousavy/nitro
5
+ /// Copyright © Marc Rousavy @ Margelo
6
+ ///
7
+
8
+ #pragma once
9
+
10
+ #if __has_include(<NitroModules/JSIConverter.hpp>)
11
+ #include <NitroModules/JSIConverter.hpp>
12
+ #else
13
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
14
+ #endif
15
+ #if __has_include(<NitroModules/NitroDefines.hpp>)
16
+ #include <NitroModules/NitroDefines.hpp>
17
+ #else
18
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
19
+ #endif
20
+ #if __has_include(<NitroModules/JSIHelpers.hpp>)
21
+ #include <NitroModules/JSIHelpers.hpp>
22
+ #else
23
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
24
+ #endif
25
+ #if __has_include(<NitroModules/PropNameIDCache.hpp>)
26
+ #include <NitroModules/PropNameIDCache.hpp>
27
+ #else
28
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
29
+ #endif
30
+
31
+ // Forward declaration of `RemoteButton` to properly resolve imports.
32
+ namespace margelo::nitro::audiobrowser { enum class RemoteButton; }
33
+
34
+ #include "RemoteButton.hpp"
35
+ #include <optional>
36
+ #include <vector>
37
+
38
+ namespace margelo::nitro::audiobrowser {
39
+
40
+ /**
41
+ * A struct which can be represented as a JavaScript object (RemoteButtonLayout).
42
+ */
43
+ struct RemoteButtonLayout final {
44
+ public:
45
+ std::optional<RemoteButton> back SWIFT_PRIVATE;
46
+ std::optional<RemoteButton> forward SWIFT_PRIVATE;
47
+ std::vector<RemoteButton> overflow SWIFT_PRIVATE;
48
+
49
+ public:
50
+ RemoteButtonLayout() = default;
51
+ explicit RemoteButtonLayout(std::optional<RemoteButton> back, std::optional<RemoteButton> forward, std::vector<RemoteButton> overflow): back(back), forward(forward), overflow(overflow) {}
52
+
53
+ public:
54
+ friend bool operator==(const RemoteButtonLayout& lhs, const RemoteButtonLayout& rhs) = default;
55
+ };
56
+
57
+ } // namespace margelo::nitro::audiobrowser
58
+
59
+ namespace margelo::nitro {
60
+
61
+ // C++ RemoteButtonLayout <> JS RemoteButtonLayout (object)
62
+ template <>
63
+ struct JSIConverter<margelo::nitro::audiobrowser::RemoteButtonLayout> final {
64
+ static inline margelo::nitro::audiobrowser::RemoteButtonLayout fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
65
+ jsi::Object obj = arg.asObject(runtime);
66
+ return margelo::nitro::audiobrowser::RemoteButtonLayout(
67
+ JSIConverter<std::optional<margelo::nitro::audiobrowser::RemoteButton>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "back"))),
68
+ JSIConverter<std::optional<margelo::nitro::audiobrowser::RemoteButton>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "forward"))),
69
+ JSIConverter<std::vector<margelo::nitro::audiobrowser::RemoteButton>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "overflow")))
70
+ );
71
+ }
72
+ static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::audiobrowser::RemoteButtonLayout& arg) {
73
+ jsi::Object obj(runtime);
74
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "back"), JSIConverter<std::optional<margelo::nitro::audiobrowser::RemoteButton>>::toJSI(runtime, arg.back));
75
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "forward"), JSIConverter<std::optional<margelo::nitro::audiobrowser::RemoteButton>>::toJSI(runtime, arg.forward));
76
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "overflow"), JSIConverter<std::vector<margelo::nitro::audiobrowser::RemoteButton>>::toJSI(runtime, arg.overflow));
77
+ return obj;
78
+ }
79
+ static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
80
+ if (!value.isObject()) {
81
+ return false;
82
+ }
83
+ jsi::Object obj = value.getObject(runtime);
84
+ if (!nitro::isPlainObject(runtime, obj)) {
85
+ return false;
86
+ }
87
+ if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::RemoteButton>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "back")))) return false;
88
+ if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::RemoteButton>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "forward")))) return false;
89
+ if (!JSIConverter<std::vector<margelo::nitro::audiobrowser::RemoteButton>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "overflow")))) return false;
90
+ return true;
91
+ }
92
+ };
93
+
94
+ } // namespace margelo::nitro
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-audio-browser",
3
- "version": "0.2.0-next.1",
3
+ "version": "0.2.0-next.11",
4
4
  "description": "react-native-audio-browser is a react native package built with Nitro",
5
5
  "keywords": [
6
6
  "react-native",
@@ -45,17 +45,20 @@
45
45
  },
46
46
  "scripts": {
47
47
  "android:format": "yarn workspace example-native android:format",
48
+ "android:format:check": "yarn workspace example-native android:format:check",
48
49
  "android:ide": "yarn workspace example-native android:ide",
49
50
  "android:logs": "react-native log-android",
50
51
  "android:test": "yarn workspace example-native android:test",
51
52
  "build": "yarn prepare",
52
53
  "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
53
54
  "codegen": "node codegen/index.js --logLevel=\"debug\" && node post-script.cjs && node codegen/strip-struct-equality.cjs && yarn build",
54
- "prepare": "bob build",
55
+ "prepare": "bob build && yarn hooks:install",
56
+ "hooks:install": "git config core.hooksPath .githooks || exit 0",
55
57
  "example": "yarn workspace example-native",
56
- "ci:format": "oxfmt --check src",
58
+ "ci:format": "oxfmt --check --ignore-path .gitignore --ignore-path .oxfmtignore .",
59
+ "ci:format:ios": "swiftformat --lint ios",
57
60
  "ci:lint": "oxlint --type-aware src",
58
- "format": "oxfmt --write",
61
+ "format": "oxfmt --write --ignore-path .gitignore --ignore-path .oxfmtignore .",
59
62
  "ios:format": "swiftformat ios",
60
63
  "ios:ide": "yarn workspace example-native ios:ide",
61
64
  "ios:rebuild": "yarn workspace example-native ios:rebuild",
@@ -69,15 +72,20 @@
69
72
  "@react-native-community/cli": "15.0.0-alpha.2",
70
73
  "@semantic-release/changelog": "^6.0.3",
71
74
  "@semantic-release/git": "^10.0.1",
75
+ "@testing-library/dom": "^10.4.1",
76
+ "@testing-library/react": "^16.3.2",
72
77
  "@types/node": "^22",
73
78
  "@types/react": "19.1.1",
79
+ "@types/react-dom": "19.1.7",
74
80
  "conventional-changelog-conventionalcommits": "^9.3.0",
75
81
  "del-cli": "^5.1.0",
82
+ "happy-dom": "^20.11.2",
76
83
  "nitrogen": "0.35.0",
77
84
  "oxfmt": "^0.27.0",
78
85
  "oxlint": "^1.42.0",
79
86
  "oxlint-tsgolint": "^0.11.2",
80
87
  "react": "19.1.1",
88
+ "react-dom": "19.1.1",
81
89
  "react-native": "0.83.0",
82
90
  "react-native-builder-bob": "^0.37.0",
83
91
  "react-native-monorepo-config": "^0.3.1",
@@ -1,4 +1,4 @@
1
+ // `./native` is deliberately not re-exported — see public-surface.test.ts.
1
2
  export * from './features'
2
- export * from './native'
3
3
  export * from './types'
4
4
  export * from './utils/useDebug'
package/src/CLAUDE.md ADDED
@@ -0,0 +1,52 @@
1
+ # TypeScript API
2
+
3
+ The rules here are about the shape of the package's public surface. Both are
4
+ enforced by tests, but the tests only tell you _after_ you've written it.
5
+
6
+ ## Everything you export is public
7
+
8
+ `index.ts` → `AudioBrowser.ts` → `features/index.ts` is a chain of unfiltered
9
+ `export *`. There is no allowlist to add a symbol to: a new `export` in any
10
+ feature module joins the package's public surface the moment you write it.
11
+
12
+ `@internal` does **not** make a value private. `stripInternal` honours it when
13
+ building `lib/typescript` — what a consumer's TypeScript sees — but React Native
14
+ resolves `"react-native": "src/index"`, so Metro bundles the _source_, where
15
+ nothing was stripped. An `@internal` value is invisible to the type checker and
16
+ fully reachable at runtime via `require()`.
17
+
18
+ So an internal value needs a module the barrels don't re-export, imported
19
+ directly by its callers — `features/player/validateOptions.ts` is the pattern.
20
+ Types are exempt: they have no runtime representation, so `stripInternal` really
21
+ does remove them, and `@internal` is enough.
22
+
23
+ `native.ts` is the sharp case and stays out of the barrel permanently. It holds
24
+ the raw Nitro object, whose `on*` properties are single callback slots that the
25
+ emitters below already occupy — a consumer assigning one unsubscribes every hook
26
+ in the library. Feature modules import it relatively; nothing else touches it.
27
+
28
+ `public-surface.test.ts` walks the `export *` graph and fails on any reachable
29
+ value that is `@internal`, `__`-prefixed, or `nativeBrowser`.
30
+
31
+ ## Events are emitters, not functions
32
+
33
+ Every `on*` export is an object you subscribe to with `addListener(cb)`, which
34
+ returns an unsubscribe function. Never export a bare `on*(cb)` subscribe
35
+ function — that split is what made the whole remote-controls guide a compile
36
+ error until it was unified.
37
+
38
+ Two emitter classes, picked by what the event _is_:
39
+
40
+ - `NativeUpdatedValue` — state with a current value (playback, options,
41
+ progress). Subscribes to native at module load so no update is missed, and
42
+ caches `lastValue` so hooks can read synchronously.
43
+ - `LazyNativeEmitter` — discrete events with no current value (remote controls,
44
+ gate hits). Assigns the native callback on the first `addListener`, so an
45
+ event nobody listens to costs nothing.
46
+
47
+ Both are created via `emitterize(cb => (nativeBrowser.onThing = cb))` and both
48
+ return the instance. Neither class is exported from the package.
49
+
50
+ `on*` observes; `handle*` overrides. `handleRemoteNext(cb)` is a plain setter
51
+ that replaces the default behaviour and takes `undefined` to clear it, while
52
+ `onRemoteNext` fires on every press regardless of who handled it.
@@ -0,0 +1,79 @@
1
+ /** @vitest-environment happy-dom */
2
+
3
+ import { renderHook, act, cleanup } from '@testing-library/react'
4
+ import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
5
+ import type { BatteryOptimizationStatus } from './battery'
6
+
7
+ const native = vi.hoisted(() => ({
8
+ getBatteryWarningPending: vi.fn(() => false),
9
+ getBatteryOptimizationStatus: vi.fn<() => BatteryOptimizationStatus>(
10
+ () => 'unknown' as BatteryOptimizationStatus
11
+ ),
12
+ dismissBatteryWarning: vi.fn(),
13
+ openBatterySettings: vi.fn(),
14
+ onBatteryWarningPendingChanged: undefined as
15
+ | ((event: { pending: boolean }) => void)
16
+ | undefined,
17
+ onBatteryOptimizationStatusChanged: undefined as
18
+ | ((event: { status: BatteryOptimizationStatus }) => void)
19
+ | undefined
20
+ }))
21
+
22
+ vi.mock('../native', () => ({ nativeBrowser: native }))
23
+
24
+ const { useBatteryWarning } = await import('./battery')
25
+
26
+ beforeEach(() => {
27
+ vi.clearAllMocks()
28
+ native.getBatteryWarningPending.mockReturnValue(false)
29
+ native.getBatteryOptimizationStatus.mockReturnValue(
30
+ 'unknown' as BatteryOptimizationStatus
31
+ )
32
+ })
33
+ afterEach(cleanup)
34
+
35
+ describe('useBatteryWarning', () => {
36
+ it('combines the two underlying values into one object', () => {
37
+ const { result } = renderHook(() => useBatteryWarning())
38
+ expect(result.current).toMatchObject({ pending: false, status: 'unknown' })
39
+ })
40
+
41
+ it('tracks each source independently', () => {
42
+ const { result } = renderHook(() => useBatteryWarning())
43
+
44
+ act(() => native.onBatteryWarningPendingChanged?.({ pending: true }))
45
+ expect(result.current).toMatchObject({ pending: true, status: 'unknown' })
46
+
47
+ act(() =>
48
+ native.onBatteryOptimizationStatusChanged?.({
49
+ status: 'restricted' as BatteryOptimizationStatus
50
+ })
51
+ )
52
+ expect(result.current).toMatchObject({
53
+ pending: true,
54
+ status: 'restricted'
55
+ })
56
+ })
57
+
58
+ it('exposes actions that reach native', () => {
59
+ const { result } = renderHook(() => useBatteryWarning())
60
+
61
+ result.current.dismiss()
62
+ expect(native.dismissBatteryWarning).toHaveBeenCalledOnce()
63
+
64
+ result.current.openSettings()
65
+ expect(native.openBatterySettings).toHaveBeenCalledOnce()
66
+ })
67
+
68
+ it('keeps the action identities stable across updates', () => {
69
+ const { result } = renderHook(() => useBatteryWarning())
70
+ const { dismiss, openSettings } = result.current
71
+
72
+ act(() => native.onBatteryWarningPendingChanged?.({ pending: true }))
73
+
74
+ // They are module-level functions, not closures — a consumer can safely put
75
+ // them in a dependency array.
76
+ expect(result.current.dismiss).toBe(dismiss)
77
+ expect(result.current.openSettings).toBe(openSettings)
78
+ })
79
+ })
@@ -169,5 +169,5 @@ export function hasSearch(): boolean {
169
169
  * ```
170
170
  */
171
171
  export async function search(query: string): Promise<Track[]> {
172
- return nativeBrowser.onSearch(query)
172
+ return nativeBrowser.search(query)
173
173
  }
@@ -19,7 +19,7 @@ export function isCarConnected(): boolean {
19
19
  * Subscribes to car connection changes (CarPlay on iOS, Android Auto /
20
20
  * Android Automotive on Android). Never fires on web.
21
21
  * @param callback - Called with the new connection state
22
- * @returns Cleanup function to unsubscribe
22
+ * @returns An emitter — subscribe with `addListener(callback)`, which returns a cleanup function
23
23
  */
24
24
  export const onCarConnectedChanged = NativeUpdatedValue.emitterize<boolean>(
25
25
  (cb) => (nativeBrowser.onCarConnectedChanged = cb)
@@ -46,7 +46,7 @@ export function setEqualizerLevels(levels: number[]): void {
46
46
  /**
47
47
  * Subscribes to equalizer settings changes (Android only).
48
48
  * @param callback - Called when equalizer settings change
49
- * @returns Cleanup function to unsubscribe
49
+ * @returns An emitter — subscribe with `addListener(callback)`, which returns a cleanup function
50
50
  */
51
51
  export const onEqualizerChanged =
52
52
  NativeUpdatedValue.emitterize<EqualizerSettings>(
@@ -134,7 +134,7 @@ export function getPlaybackError(): PlaybackError | undefined {
134
134
  /**
135
135
  * Subscribes to playback error events.
136
136
  * @param callback - Called when a playback error occurs
137
- * @returns Cleanup function to unsubscribe
137
+ * @returns An emitter — subscribe with `addListener(callback)`, which returns a cleanup function
138
138
  */
139
139
  export const onPlaybackError =
140
140
  NativeUpdatedValue.emitterize<PlaybackErrorEvent>(
@@ -165,7 +165,7 @@ export function getNavigationError(): NavigationError | undefined {
165
165
  /**
166
166
  * Subscribes to navigation error events.
167
167
  * @param callback - Called when a navigation error occurs
168
- * @returns Cleanup function to unsubscribe
168
+ * @returns An emitter — subscribe with `addListener(callback)`, which returns a cleanup function
169
169
  */
170
170
  export const onNavigationError =
171
171
  NativeUpdatedValue.emitterize<NavigationErrorEvent>(
@@ -198,7 +198,7 @@ export function getFormattedNavigationError():
198
198
  /**
199
199
  * Subscribes to formatted navigation error changes.
200
200
  * @param callback - Called when the formatted navigation error changes
201
- * @returns Cleanup function to unsubscribe
201
+ * @returns An emitter — subscribe with `addListener(callback)`, which returns a cleanup function
202
202
  */
203
203
  export const onFormattedNavigationError = NativeUpdatedValue.emitterize<
204
204
  FormattedNavigationError | undefined
@@ -82,7 +82,7 @@ export interface FavoriteChangedEvent {
82
82
  * The native side has already updated the track's favorite state and UI.
83
83
  *
84
84
  * @param callback - Called with the track and its new favorite state
85
- * @returns Cleanup function to unsubscribe
85
+ * @returns An emitter — subscribe with `addListener(callback)`, which returns a cleanup function
86
86
  *
87
87
  * @example
88
88
  * ```ts
@@ -120,12 +120,20 @@ nativeBrowser.resolveGate = async (
120
120
  * some surfaces (CarPlay) any gate change pops pushed navigation back to root,
121
121
  * so a page the user had drilled into is reset to the tab root. Set the gate
122
122
  * before the car connects and it'll be there the moment it does.
123
+ *
124
+ * @platform ios android
125
+ * A no-op on web, which has no CarPlay or Android Auto surfaces for the gate to
126
+ * cover. Nothing is lost: the gate never covered in-app browse UI on any
127
+ * platform — that stays yours to gate.
123
128
  */
124
129
  export function setGate(gate: Gate, resolve?: GateResolver): void
125
130
  /**
126
131
  * Raises the gate with a resolver only (no default chrome).
127
132
  * The resolver must return a {@link Gate} or `true` for gated requests;
128
133
  * native uses the built-in fallback chrome when `true` and no default is set.
134
+ *
135
+ * @platform ios android
136
+ * A no-op on web — the resolver is never consulted there.
129
137
  */
130
138
  export function setGate(resolve: GateResolver): void
131
139
  export function setGate(a: Gate | GateResolver, b?: GateResolver): void {
@@ -140,6 +148,9 @@ export function setGate(a: Gate | GateResolver, b?: GateResolver): void {
140
148
 
141
149
  /**
142
150
  * Drops the gate — the real content comes back, and the current tab is kept.
151
+ *
152
+ * @platform ios android
153
+ * A no-op on web, where no gate was ever raised.
143
154
  */
144
155
  export function clearGate(): void {
145
156
  resolver = undefined
@@ -148,7 +159,11 @@ export function clearGate(): void {
148
159
 
149
160
  /**
150
161
  * Subscribes to gate events (fired when a request is gated).
151
- * @returns Cleanup function to unsubscribe.
162
+ *
163
+ * @platform ios android
164
+ * Never fires on web — there are no gated serves to report.
165
+ *
166
+ * @returns An emitter — subscribe with `addListener(callback)`, which returns a cleanup function
152
167
  */
153
168
  export const onGate = LazyNativeEmitter.emitterize<GateEvent>(
154
169
  (cb) => (nativeBrowser.onGate = cb)