react-native-audio-browser 0.2.0-next.2 → 0.2.0-next.20

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 (660) hide show
  1. package/README.md +35 -21
  2. package/android/build.gradle +35 -12
  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 +389 -164
  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 +315 -213
  10. package/android/src/main/java/com/audiobrowser/browser/BrowserUrlResolution.kt +24 -5
  11. package/android/src/main/java/com/audiobrowser/browser/InertStyleDiagnostic.kt +267 -0
  12. package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +97 -58
  13. package/android/src/main/java/com/audiobrowser/browser/SectionScope.kt +70 -29
  14. package/android/src/main/java/com/audiobrowser/browser/StyleResolver.kt +60 -0
  15. package/android/src/main/java/com/audiobrowser/extension/ResolvedTrackExt.kt +20 -7
  16. package/android/src/main/java/com/audiobrowser/extension/TappedTrack.kt +20 -0
  17. package/android/src/main/java/com/audiobrowser/extension/TrackIdentity.kt +15 -0
  18. package/android/src/main/java/com/audiobrowser/http/HttpClient.kt +20 -3
  19. package/android/src/main/java/com/audiobrowser/model/IcyTitle.kt +24 -0
  20. package/android/src/main/java/com/audiobrowser/model/PlaybackMetadata.kt +10 -6
  21. package/android/src/main/java/com/audiobrowser/model/PlayerUpdateOptions.kt +12 -12
  22. package/android/src/main/java/com/audiobrowser/player/CapabilityControls.kt +111 -58
  23. package/android/src/main/java/com/audiobrowser/player/CrossOriginHeaderStripper.kt +77 -0
  24. package/android/src/main/java/com/audiobrowser/player/MediaFactory.kt +28 -10
  25. package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +509 -230
  26. package/android/src/main/java/com/audiobrowser/player/MediaSessionCommandManager.kt +218 -252
  27. package/android/src/main/java/com/audiobrowser/player/NowPlayingUpdater.kt +21 -25
  28. package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +113 -78
  29. package/android/src/main/java/com/audiobrowser/player/Player.kt +81 -38
  30. package/android/src/main/java/com/audiobrowser/player/PlayerCapabilitiesExt.kt +2 -15
  31. package/android/src/main/java/com/audiobrowser/player/PlayerListener.kt +1 -1
  32. package/android/src/main/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicy.kt +2 -1
  33. package/android/src/main/java/com/audiobrowser/player/ShuffleOrderLedBy.kt +30 -0
  34. package/android/src/main/java/com/audiobrowser/tls/AiaCertChaser.kt +67 -11
  35. package/android/src/main/java/com/audiobrowser/tls/AiaChasingExtendedTrustManager.kt +168 -0
  36. package/android/src/main/java/com/audiobrowser/tls/AiaChasingTrustManager.kt +58 -14
  37. package/android/src/main/java/com/audiobrowser/tls/AiaTls.kt +35 -7
  38. package/android/src/main/java/com/audiobrowser/tls/CachingCertificateFetcher.kt +278 -59
  39. package/android/src/main/java/com/audiobrowser/util/ArtworkVariant.kt +7 -9
  40. package/android/src/main/java/com/audiobrowser/util/BrowserPathHelper.kt +56 -40
  41. package/android/src/main/java/com/audiobrowser/util/MediaExtrasBuilder.kt +28 -23
  42. package/android/src/main/java/com/audiobrowser/util/StyleWire.kt +108 -0
  43. package/android/src/main/java/com/audiobrowser/util/TrackFactory.kt +56 -52
  44. package/android/src/main/res/values/strings.xml +25 -5
  45. package/android/src/test/java/com/audiobrowser/ServiceBindingTest.kt +87 -0
  46. package/android/src/test/java/com/audiobrowser/TestFixtures.kt +119 -33
  47. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerFavoritesTest.kt +153 -0
  48. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerLayerResolutionTest.kt +15 -0
  49. package/android/src/test/java/com/audiobrowser/browser/BrowserManagerTest.kt +346 -8
  50. package/android/src/test/java/com/audiobrowser/browser/BrowserUrlResolutionTest.kt +38 -0
  51. package/android/src/test/java/com/audiobrowser/browser/InertStyleDiagnosticTest.kt +277 -0
  52. package/android/src/test/java/com/audiobrowser/browser/JsonArtworkTest.kt +3 -2
  53. package/android/src/test/java/com/audiobrowser/browser/JsonStyleTest.kt +147 -0
  54. package/android/src/test/java/com/audiobrowser/browser/SectionScopeTest.kt +128 -55
  55. package/android/src/test/java/com/audiobrowser/browser/StyleResolverTest.kt +154 -0
  56. package/android/src/test/java/com/audiobrowser/extension/TappedTrackTest.kt +43 -0
  57. package/android/src/test/java/com/audiobrowser/extension/TrackIdentityTest.kt +41 -0
  58. package/android/src/test/java/com/audiobrowser/model/IcyTitleTest.kt +49 -0
  59. package/android/src/test/java/com/audiobrowser/player/BrowseTilesTest.kt +385 -0
  60. package/android/src/test/java/com/audiobrowser/player/CapabilityControlsTest.kt +101 -58
  61. package/android/src/test/java/com/audiobrowser/player/CrossOriginHeaderStripperTest.kt +94 -0
  62. package/android/src/test/java/com/audiobrowser/player/MediaSessionSlotMappingTest.kt +45 -0
  63. package/android/src/test/java/com/audiobrowser/player/NowPlayingUpdaterTest.kt +42 -2
  64. package/android/src/test/java/com/audiobrowser/player/PlaybackErrorClassifierTest.kt +3 -4
  65. package/android/src/test/java/com/audiobrowser/player/PlaybackStateStoreTrackJsonTest.kt +55 -0
  66. package/android/src/test/java/com/audiobrowser/player/RetryLoadErrorHandlingPolicyTest.kt +3 -3
  67. package/android/src/test/java/com/audiobrowser/player/ShuffleOrderLedByTest.kt +79 -0
  68. package/android/src/test/java/com/audiobrowser/tls/AiaCertChaserTest.kt +197 -7
  69. package/android/src/test/java/com/audiobrowser/tls/AiaChasingTrustManagerTest.kt +325 -4
  70. package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherCallSiteTest.kt +322 -0
  71. package/android/src/test/java/com/audiobrowser/tls/CachingCertificateFetcherTest.kt +83 -0
  72. package/android/src/test/java/com/audiobrowser/util/BrowserPathHelperTest.kt +41 -16
  73. package/android/src/test/java/com/audiobrowser/util/MediaExtrasBuilderTest.kt +162 -0
  74. package/android/src/test/java/com/audiobrowser/util/TrackFactoryMediaIdTest.kt +7 -7
  75. package/ios/Browser/BrowserConfig.swift +102 -5
  76. package/ios/Browser/BrowserManager+URLResolution.swift +18 -14
  77. package/ios/Browser/BrowserManager.swift +230 -205
  78. package/ios/Browser/BrowserPathHelper.swift +44 -44
  79. package/ios/Browser/InertStyleDiagnostic.swift +279 -0
  80. package/ios/Browser/JsonModels.swift +264 -106
  81. package/ios/Browser/SearchDrillIn.swift +7 -7
  82. package/ios/Browser/SectionPresentation.swift +64 -0
  83. package/ios/Browser/SectionScope.swift +58 -24
  84. package/ios/Browser/StyleResolver.swift +58 -0
  85. package/ios/Browser/TabBarEntries.swift +9 -3
  86. package/ios/Browser/TrackIdTemplate.swift +37 -0
  87. package/ios/CarPlay/CarPlayArtworkResolver.swift +8 -7
  88. package/ios/CarPlay/CarPlayController.swift +227 -85
  89. package/ios/CarPlay/CarPlayImageLoader.swift +42 -20
  90. package/ios/CarPlay/CarPlayListItemFactory.swift +289 -84
  91. package/ios/CarPlay/CarPlayNowPlayingManager.swift +15 -12
  92. package/ios/CarPlay/RNABMediaAddHandler.swift +6 -6
  93. package/ios/CarPlay/RNABMediaAffinityHandler.swift +2 -2
  94. package/ios/CarPlay/RNABMediaIntentHandler.swift +16 -16
  95. package/ios/Extension/Capability+RemoteCommand.swift +1 -1
  96. package/ios/Extension/PlayerCapabilities+Favorite.swift +1 -15
  97. package/ios/Extension/ResolvedTrack+Copying.swift +13 -15
  98. package/ios/Extension/Section+Copying.swift +29 -0
  99. package/ios/Extension/String+IcyCharset.swift +21 -0
  100. package/ios/Extension/TimedMetadata+AVFoundation.swift +6 -4
  101. package/ios/Extension/Track+Copying.swift +8 -12
  102. package/ios/Extension/Track+Identity.swift +18 -0
  103. package/ios/Extension/UIApplication+ActiveScene.swift +27 -0
  104. package/ios/Http/HttpClient.swift +8 -2
  105. package/ios/HybridAudioBrowser.swift +253 -100
  106. package/ios/Model/NitroTypeStubs.swift +125 -23
  107. package/ios/Model/PlayerUpdateOptions.swift +7 -0
  108. package/ios/Model/RemoteCommand.swift +18 -0
  109. package/ios/Model/TrackPlayerError.swift +2 -2
  110. package/ios/Option/SessionCategories.swift +3 -2
  111. package/ios/Player/MediaIntentCriteria.swift +17 -9
  112. package/ios/Player/MediaLoader.swift +33 -9
  113. package/ios/Player/NowPlayingUpdater.swift +54 -6
  114. package/ios/Player/PlaybackCoordinator.swift +13 -6
  115. package/ios/Player/PlaybackErrorHandler.swift +4 -4
  116. package/ios/Player/PlaybackTimer.swift +8 -2
  117. package/ios/Player/QueueManager.swift +46 -13
  118. package/ios/Player/RetryManager.swift +80 -18
  119. package/ios/Player/SeekCompletionHandler.swift +3 -1
  120. package/ios/Player/ShuffleOrder.swift +33 -0
  121. package/ios/Player/SleepTimerHandling.swift +13 -0
  122. package/ios/RemoteCommand/RemoteCommandCallbacks.swift +47 -0
  123. package/ios/RemoteCommand/RemoteCommandController.swift +62 -24
  124. package/ios/Tests/BrowserPathHelperTests.swift +50 -20
  125. package/ios/Tests/CarPlayArtworkResolverTests.swift +24 -41
  126. package/ios/Tests/InertStyleDiagnosticTests.swift +200 -0
  127. package/ios/Tests/JsonModelsTests.swift +150 -1
  128. package/ios/Tests/LRUCacheTests.swift +111 -0
  129. package/ios/Tests/LoadSeekCoordinatorTests.swift +3 -1
  130. package/ios/Tests/MediaIntentCriteriaTests.swift +2 -2
  131. package/ios/Tests/PlaybackCoordinatorTests.swift +1 -1
  132. package/ios/Tests/PlaybackErrorHandlerTests.swift +3 -1
  133. package/ios/Tests/PlaybackStateStoreTests.swift +4 -3
  134. package/ios/Tests/PlayerTimeObserverTests.swift +37 -0
  135. package/ios/Tests/QueueManagerTests.swift +122 -10
  136. package/ios/Tests/RemoteCommandControllerTests.swift +172 -0
  137. package/ios/Tests/RemoteCommandTests.swift +67 -0
  138. package/ios/Tests/ResolvedTrackCopyingTests.swift +39 -35
  139. package/ios/Tests/RetryManagerTests.swift +89 -0
  140. package/ios/Tests/SearchDrillInTests.swift +16 -16
  141. package/ios/Tests/SectionPresentationTests.swift +90 -0
  142. package/ios/Tests/SectionScopeTests.swift +87 -55
  143. package/ios/Tests/StyleResolverTests.swift +127 -0
  144. package/ios/Tests/Support/TestTypes.swift +8 -1
  145. package/ios/Tests/TabBarEntriesTests.swift +19 -19
  146. package/ios/Tests/TimedMetadataAVFoundationTests.swift +42 -0
  147. package/ios/Tests/TrackIdTemplateTests.swift +67 -0
  148. package/ios/Tests/TrackIdentityTests.swift +20 -0
  149. package/ios/Tests/TrackSelectorTests.swift +168 -33
  150. package/ios/TrackPlayer.swift +63 -35
  151. package/ios/TrackPlayerCallbacks.swift +5 -38
  152. package/ios/TrackSelector.swift +45 -30
  153. package/ios/Util/ArtworkImageFetcher.swift +16 -1
  154. package/ios/Util/LRUCache.swift +4 -1
  155. package/ios/Util/NetworkMonitor.swift +43 -26
  156. package/ios/Util/SFSymbolRenderer.swift +24 -2
  157. package/ios/Util/SVGProcessor.swift +9 -2
  158. package/lib/commonjs/AudioBrowser.js +8 -8
  159. package/lib/commonjs/AudioBrowser.js.map +1 -1
  160. package/lib/commonjs/CLAUDE.md +52 -0
  161. package/lib/commonjs/features/browser-config.js +12 -8
  162. package/lib/commonjs/features/browser-config.js.map +1 -1
  163. package/lib/commonjs/features/browser.js +11 -3
  164. package/lib/commonjs/features/browser.js.map +1 -1
  165. package/lib/commonjs/features/carConnection.js +1 -1
  166. package/lib/commonjs/features/equalizer.js +1 -1
  167. package/lib/commonjs/features/errors.js +3 -3
  168. package/lib/commonjs/features/favorites.js +14 -11
  169. package/lib/commonjs/features/favorites.js.map +1 -1
  170. package/lib/commonjs/features/gate.js +16 -1
  171. package/lib/commonjs/features/gate.js.map +1 -1
  172. package/lib/commonjs/features/metadata.js +20 -3
  173. package/lib/commonjs/features/metadata.js.map +1 -1
  174. package/lib/commonjs/features/network.js +1 -1
  175. package/lib/commonjs/features/nowPlaying.js +1 -1
  176. package/lib/commonjs/features/output.js +1 -1
  177. package/lib/commonjs/features/playback/controls.js +4 -2
  178. package/lib/commonjs/features/playback/controls.js.map +1 -1
  179. package/lib/commonjs/features/playback/playWhenReady.js +1 -1
  180. package/lib/commonjs/features/playback/playing.js +1 -1
  181. package/lib/commonjs/features/playback/progress.js +3 -2
  182. package/lib/commonjs/features/playback/progress.js.map +1 -1
  183. package/lib/commonjs/features/playback/rate.js +8 -1
  184. package/lib/commonjs/features/playback/rate.js.map +1 -1
  185. package/lib/commonjs/features/playback/state.js +3 -4
  186. package/lib/commonjs/features/playback/state.js.map +1 -1
  187. package/lib/commonjs/features/playback/trackPlaybackTime.js +0 -6
  188. package/lib/commonjs/features/playback/trackPlaybackTime.js.map +1 -1
  189. package/lib/commonjs/features/playback/volume.js +1 -1
  190. package/lib/commonjs/features/player/options.js +48 -34
  191. package/lib/commonjs/features/player/options.js.map +1 -1
  192. package/lib/commonjs/features/player/setup.js +18 -9
  193. package/lib/commonjs/features/player/setup.js.map +1 -1
  194. package/lib/commonjs/features/player/validateOptions.js +23 -0
  195. package/lib/commonjs/features/player/validateOptions.js.map +1 -0
  196. package/lib/commonjs/features/queue/activeTrack.js +15 -4
  197. package/lib/commonjs/features/queue/activeTrack.js.map +1 -1
  198. package/lib/commonjs/features/queue/queue.js +13 -6
  199. package/lib/commonjs/features/queue/queue.js.map +1 -1
  200. package/lib/commonjs/features/queue/repeatMode.js +1 -1
  201. package/lib/commonjs/features/queue/shuffle.js +1 -1
  202. package/lib/commonjs/features/remoteControls.js +13 -92
  203. package/lib/commonjs/features/remoteControls.js.map +1 -1
  204. package/lib/commonjs/features/sleepTimer.js +13 -1
  205. package/lib/commonjs/features/sleepTimer.js.map +1 -1
  206. package/lib/commonjs/test-utils/reactNativeStub.js +65 -0
  207. package/lib/commonjs/test-utils/reactNativeStub.js.map +1 -0
  208. package/lib/commonjs/utils/LazyNativeEmitter.js +28 -14
  209. package/lib/commonjs/utils/LazyNativeEmitter.js.map +1 -1
  210. package/lib/commonjs/utils/NativeUpdatedValue.js +31 -13
  211. package/lib/commonjs/utils/NativeUpdatedValue.js.map +1 -1
  212. package/lib/commonjs/utils/getTrackIdentity.js +24 -0
  213. package/lib/commonjs/utils/getTrackIdentity.js.map +1 -0
  214. package/lib/commonjs/utils/useNativeValueRefreshedBy.js +33 -0
  215. package/lib/commonjs/utils/useNativeValueRefreshedBy.js.map +1 -0
  216. package/lib/commonjs/web/NativeAudioBrowser.js +200 -75
  217. package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
  218. package/lib/commonjs/web/TrackPlayer/LoadAttempt.js +37 -0
  219. package/lib/commonjs/web/TrackPlayer/LoadAttempt.js.map +1 -0
  220. package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js +18 -2
  221. package/lib/commonjs/web/TrackPlayer/PlaybackStateMachine.js.map +1 -1
  222. package/lib/commonjs/web/TrackPlayer/Player.js +254 -39
  223. package/lib/commonjs/web/TrackPlayer/Player.js.map +1 -1
  224. package/lib/commonjs/web/TrackPlayer/QueueManager.js +14 -0
  225. package/lib/commonjs/web/TrackPlayer/QueueManager.js.map +1 -1
  226. package/lib/commonjs/web/TrackPlayer/QueuePlayer.js +33 -12
  227. package/lib/commonjs/web/TrackPlayer/QueuePlayer.js.map +1 -1
  228. package/lib/commonjs/web/browser/BrowserManager.js +175 -100
  229. package/lib/commonjs/web/browser/BrowserManager.js.map +1 -1
  230. package/lib/commonjs/web/browser/FavoriteManager.js +30 -21
  231. package/lib/commonjs/web/browser/FavoriteManager.js.map +1 -1
  232. package/lib/commonjs/web/browser/SearchManager.js +18 -23
  233. package/lib/commonjs/web/browser/SearchManager.js.map +1 -1
  234. package/lib/commonjs/web/browser/assertBrowsePageShape.js +2 -2
  235. package/lib/commonjs/web/browser/assertBrowsePageShape.js.map +1 -1
  236. package/lib/commonjs/web/browser/classifyTrackNavigation.js +9 -9
  237. package/lib/commonjs/web/browser/classifyTrackNavigation.js.map +1 -1
  238. package/lib/commonjs/web/browser/sections.js +89 -0
  239. package/lib/commonjs/web/browser/sections.js.map +1 -0
  240. package/lib/commonjs/web/http/RequestConfigBuilder.js +110 -27
  241. package/lib/commonjs/web/http/RequestConfigBuilder.js.map +1 -1
  242. package/lib/commonjs/web/http/followMediaRedirect.js +219 -0
  243. package/lib/commonjs/web/http/followMediaRedirect.js.map +1 -0
  244. package/lib/commonjs/web/player/NowPlayingManager.js +4 -3
  245. package/lib/commonjs/web/player/NowPlayingManager.js.map +1 -1
  246. package/lib/commonjs/web/util/BrowserPathHelper.js +56 -11
  247. package/lib/commonjs/web/util/BrowserPathHelper.js.map +1 -1
  248. package/lib/module/AudioBrowser.js +2 -1
  249. package/lib/module/AudioBrowser.js.map +1 -1
  250. package/lib/module/CLAUDE.md +52 -0
  251. package/lib/module/features/browser-config.js +12 -8
  252. package/lib/module/features/browser-config.js.map +1 -1
  253. package/lib/module/features/browser.js +11 -3
  254. package/lib/module/features/browser.js.map +1 -1
  255. package/lib/module/features/carConnection.js +1 -1
  256. package/lib/module/features/equalizer.js +1 -1
  257. package/lib/module/features/errors.js +3 -3
  258. package/lib/module/features/favorites.js +14 -11
  259. package/lib/module/features/favorites.js.map +1 -1
  260. package/lib/module/features/gate.js +16 -1
  261. package/lib/module/features/gate.js.map +1 -1
  262. package/lib/module/features/metadata.js +20 -3
  263. package/lib/module/features/metadata.js.map +1 -1
  264. package/lib/module/features/network.js +1 -1
  265. package/lib/module/features/nowPlaying.js +1 -1
  266. package/lib/module/features/output.js +1 -1
  267. package/lib/module/features/playback/controls.js +4 -2
  268. package/lib/module/features/playback/controls.js.map +1 -1
  269. package/lib/module/features/playback/playWhenReady.js +1 -1
  270. package/lib/module/features/playback/playing.js +1 -1
  271. package/lib/module/features/playback/progress.js +3 -2
  272. package/lib/module/features/playback/progress.js.map +1 -1
  273. package/lib/module/features/playback/rate.js +8 -1
  274. package/lib/module/features/playback/rate.js.map +1 -1
  275. package/lib/module/features/playback/state.js +3 -4
  276. package/lib/module/features/playback/state.js.map +1 -1
  277. package/lib/module/features/playback/trackPlaybackTime.js +0 -5
  278. package/lib/module/features/playback/trackPlaybackTime.js.map +1 -1
  279. package/lib/module/features/playback/volume.js +1 -1
  280. package/lib/module/features/player/options.js +47 -32
  281. package/lib/module/features/player/options.js.map +1 -1
  282. package/lib/module/features/player/setup.js +17 -8
  283. package/lib/module/features/player/setup.js.map +1 -1
  284. package/lib/module/features/player/validateOptions.js +19 -0
  285. package/lib/module/features/player/validateOptions.js.map +1 -0
  286. package/lib/module/features/queue/activeTrack.js +15 -4
  287. package/lib/module/features/queue/activeTrack.js.map +1 -1
  288. package/lib/module/features/queue/queue.js +13 -6
  289. package/lib/module/features/queue/queue.js.map +1 -1
  290. package/lib/module/features/queue/repeatMode.js +1 -1
  291. package/lib/module/features/queue/shuffle.js +1 -1
  292. package/lib/module/features/remoteControls.js +13 -92
  293. package/lib/module/features/remoteControls.js.map +1 -1
  294. package/lib/module/features/sleepTimer.js +13 -1
  295. package/lib/module/features/sleepTimer.js.map +1 -1
  296. package/lib/module/test-utils/reactNativeStub.js +58 -0
  297. package/lib/module/test-utils/reactNativeStub.js.map +1 -0
  298. package/lib/module/utils/LazyNativeEmitter.js +28 -14
  299. package/lib/module/utils/LazyNativeEmitter.js.map +1 -1
  300. package/lib/module/utils/NativeUpdatedValue.js +31 -13
  301. package/lib/module/utils/NativeUpdatedValue.js.map +1 -1
  302. package/lib/module/utils/getTrackIdentity.js +20 -0
  303. package/lib/module/utils/getTrackIdentity.js.map +1 -0
  304. package/lib/module/utils/useNativeValueRefreshedBy.js +29 -0
  305. package/lib/module/utils/useNativeValueRefreshedBy.js.map +1 -0
  306. package/lib/module/web/NativeAudioBrowser.js +200 -75
  307. package/lib/module/web/NativeAudioBrowser.js.map +1 -1
  308. package/lib/module/web/TrackPlayer/LoadAttempt.js +32 -0
  309. package/lib/module/web/TrackPlayer/LoadAttempt.js.map +1 -0
  310. package/lib/module/web/TrackPlayer/PlaybackStateMachine.js +18 -2
  311. package/lib/module/web/TrackPlayer/PlaybackStateMachine.js.map +1 -1
  312. package/lib/module/web/TrackPlayer/Player.js +254 -39
  313. package/lib/module/web/TrackPlayer/Player.js.map +1 -1
  314. package/lib/module/web/TrackPlayer/QueueManager.js +14 -0
  315. package/lib/module/web/TrackPlayer/QueueManager.js.map +1 -1
  316. package/lib/module/web/TrackPlayer/QueuePlayer.js +33 -12
  317. package/lib/module/web/TrackPlayer/QueuePlayer.js.map +1 -1
  318. package/lib/module/web/browser/BrowserManager.js +175 -100
  319. package/lib/module/web/browser/BrowserManager.js.map +1 -1
  320. package/lib/module/web/browser/FavoriteManager.js +31 -21
  321. package/lib/module/web/browser/FavoriteManager.js.map +1 -1
  322. package/lib/module/web/browser/SearchManager.js +18 -23
  323. package/lib/module/web/browser/SearchManager.js.map +1 -1
  324. package/lib/module/web/browser/assertBrowsePageShape.js +2 -2
  325. package/lib/module/web/browser/assertBrowsePageShape.js.map +1 -1
  326. package/lib/module/web/browser/classifyTrackNavigation.js +9 -9
  327. package/lib/module/web/browser/classifyTrackNavigation.js.map +1 -1
  328. package/lib/module/web/browser/sections.js +83 -0
  329. package/lib/module/web/browser/sections.js.map +1 -0
  330. package/lib/module/web/http/RequestConfigBuilder.js +110 -27
  331. package/lib/module/web/http/RequestConfigBuilder.js.map +1 -1
  332. package/lib/module/web/http/followMediaRedirect.js +215 -0
  333. package/lib/module/web/http/followMediaRedirect.js.map +1 -0
  334. package/lib/module/web/player/NowPlayingManager.js +4 -3
  335. package/lib/module/web/player/NowPlayingManager.js.map +1 -1
  336. package/lib/module/web/util/BrowserPathHelper.js +56 -11
  337. package/lib/module/web/util/BrowserPathHelper.js.map +1 -1
  338. package/lib/typescript/package.json +1 -0
  339. package/lib/typescript/src/AudioBrowser.d.ts +1 -1
  340. package/lib/typescript/src/AudioBrowser.d.ts.map +1 -1
  341. package/lib/typescript/src/features/browser-config.d.ts.map +1 -1
  342. package/lib/typescript/src/features/browser.d.ts +10 -2
  343. package/lib/typescript/src/features/browser.d.ts.map +1 -1
  344. package/lib/typescript/src/features/carConnection.d.ts +1 -1
  345. package/lib/typescript/src/features/equalizer.d.ts +1 -1
  346. package/lib/typescript/src/features/errors.d.ts +3 -3
  347. package/lib/typescript/src/features/favorites.d.ts +14 -11
  348. package/lib/typescript/src/features/favorites.d.ts.map +1 -1
  349. package/lib/typescript/src/features/gate.d.ts +18 -2
  350. package/lib/typescript/src/features/gate.d.ts.map +1 -1
  351. package/lib/typescript/src/features/metadata.d.ts +20 -3
  352. package/lib/typescript/src/features/metadata.d.ts.map +1 -1
  353. package/lib/typescript/src/features/network.d.ts +1 -1
  354. package/lib/typescript/src/features/nowPlaying.d.ts +1 -1
  355. package/lib/typescript/src/features/output.d.ts +1 -1
  356. package/lib/typescript/src/features/playback/controls.d.ts +4 -2
  357. package/lib/typescript/src/features/playback/controls.d.ts.map +1 -1
  358. package/lib/typescript/src/features/playback/playWhenReady.d.ts +1 -1
  359. package/lib/typescript/src/features/playback/playing.d.ts +1 -1
  360. package/lib/typescript/src/features/playback/progress.d.ts +1 -1
  361. package/lib/typescript/src/features/playback/progress.d.ts.map +1 -1
  362. package/lib/typescript/src/features/playback/rate.d.ts +8 -1
  363. package/lib/typescript/src/features/playback/rate.d.ts.map +1 -1
  364. package/lib/typescript/src/features/playback/state.d.ts +3 -4
  365. package/lib/typescript/src/features/playback/state.d.ts.map +1 -1
  366. package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts +1 -1
  367. package/lib/typescript/src/features/playback/trackPlaybackTime.d.ts.map +1 -1
  368. package/lib/typescript/src/features/playback/volume.d.ts +1 -1
  369. package/lib/typescript/src/features/player/options.d.ts +108 -56
  370. package/lib/typescript/src/features/player/options.d.ts.map +1 -1
  371. package/lib/typescript/src/features/player/setup.d.ts +14 -4
  372. package/lib/typescript/src/features/player/setup.d.ts.map +1 -1
  373. package/lib/typescript/src/features/player/validateOptions.d.ts +2 -0
  374. package/lib/typescript/src/features/player/validateOptions.d.ts.map +1 -0
  375. package/lib/typescript/src/features/queue/activeTrack.d.ts +9 -2
  376. package/lib/typescript/src/features/queue/activeTrack.d.ts.map +1 -1
  377. package/lib/typescript/src/features/queue/queue.d.ts +7 -4
  378. package/lib/typescript/src/features/queue/queue.d.ts.map +1 -1
  379. package/lib/typescript/src/features/queue/repeatMode.d.ts +1 -1
  380. package/lib/typescript/src/features/queue/shuffle.d.ts +1 -1
  381. package/lib/typescript/src/features/remoteControls.d.ts +23 -22
  382. package/lib/typescript/src/features/remoteControls.d.ts.map +1 -1
  383. package/lib/typescript/src/features/sleepTimer.d.ts +1 -1
  384. package/lib/typescript/src/features/sleepTimer.d.ts.map +1 -1
  385. package/lib/typescript/src/test-utils/reactNativeStub.d.ts +36 -0
  386. package/lib/typescript/src/test-utils/reactNativeStub.d.ts.map +1 -0
  387. package/lib/typescript/src/types/browser-native.d.ts +3 -2
  388. package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
  389. package/lib/typescript/src/types/browser-nodes.d.ts +380 -126
  390. package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
  391. package/lib/typescript/src/types/browser.d.ts +82 -57
  392. package/lib/typescript/src/types/browser.d.ts.map +1 -1
  393. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts +19 -16
  394. package/lib/typescript/src/utils/LazyNativeEmitter.d.ts.map +1 -1
  395. package/lib/typescript/src/utils/NativeUpdatedValue.d.ts +24 -19
  396. package/lib/typescript/src/utils/NativeUpdatedValue.d.ts.map +1 -1
  397. package/lib/typescript/src/utils/getTrackIdentity.d.ts +18 -0
  398. package/lib/typescript/src/utils/getTrackIdentity.d.ts.map +1 -0
  399. package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts +21 -0
  400. package/lib/typescript/src/utils/useNativeValueRefreshedBy.d.ts.map +1 -0
  401. package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +1 -2
  402. package/nitrogen/generated/android/AudioBrowserOnLoad.cpp +2 -0
  403. package/nitrogen/generated/android/c++/JAndroidOptions.hpp +10 -10
  404. package/nitrogen/generated/android/c++/{JFavoritesMatchMode.hpp → JArtworkRendering.hpp} +15 -15
  405. package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +8 -3
  406. package/nitrogen/generated/android/c++/JBrowseResult.hpp +16 -4
  407. package/nitrogen/generated/android/c++/JCarPlayPlayingIndicatorLocation.hpp +58 -0
  408. package/nitrogen/generated/android/c++/JCardImage.hpp +58 -0
  409. package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +8 -3
  410. package/nitrogen/generated/android/c++/JFormatNowPlayingParams.hpp +8 -3
  411. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_RequestConfig___Track.hpp +8 -3
  412. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_NowPlayingUpdate____FormatNowPlayingParams.hpp +8 -3
  413. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_std__string____Track.hpp +8 -3
  414. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +8 -3
  415. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +8 -2
  416. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +8 -2
  417. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__string__.hpp +102 -0
  418. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError__std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError_______BrowserSourceCallbackParam.hpp +16 -4
  419. package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +8 -3
  420. package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +7 -10
  421. package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +8 -3
  422. package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +15 -3
  423. package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +8 -2
  424. package/nitrogen/generated/android/c++/JGridTile.hpp +61 -0
  425. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +45 -25
  426. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.hpp +1 -1
  427. package/nitrogen/generated/android/c++/JIOSOptions.hpp +9 -3
  428. package/nitrogen/generated/android/c++/JImageShape.hpp +58 -0
  429. package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +8 -3
  430. package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +36 -11
  431. package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +14 -2
  432. package/nitrogen/generated/android/c++/JNativeSetupPlayerOptions.hpp +15 -12
  433. package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +7 -10
  434. package/nitrogen/generated/android/c++/JNitroAndroidUpdateOptions.hpp +10 -10
  435. package/nitrogen/generated/android/c++/JNitroIOSUpdateOptions.hpp +9 -3
  436. package/nitrogen/generated/android/c++/JOptions.hpp +7 -10
  437. package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +8 -3
  438. package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +5 -11
  439. package/nitrogen/generated/android/c++/{JNotificationButton.hpp → JRemoteButton.hpp} +19 -19
  440. package/nitrogen/generated/android/c++/JRemoteButtonLayout.hpp +86 -0
  441. package/nitrogen/generated/android/c++/JResolvedTrack.hpp +57 -49
  442. package/nitrogen/generated/android/c++/JSection.hpp +116 -0
  443. package/nitrogen/generated/android/c++/JSectionStyle.hpp +96 -0
  444. package/nitrogen/generated/android/c++/JStyleDisplay.hpp +58 -0
  445. package/nitrogen/generated/android/c++/JTrack.hpp +25 -46
  446. package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +8 -2
  447. package/nitrogen/generated/android/c++/JTrackStyle.hpp +46 -18
  448. package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.cpp +26 -0
  449. package/nitrogen/generated/android/c++/JVariant_NullType_RemoteButtonLayout.hpp +75 -0
  450. package/nitrogen/generated/android/c++/JVariant_ResolvedTrack_BrowseError_Promise_BrowseResult_.hpp +16 -4
  451. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidOptions.kt +3 -3
  452. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoritesMatchMode.kt → ArtworkRendering.kt} +5 -5
  453. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayPlayingIndicatorLocation.kt +23 -0
  454. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CardImage.kt +23 -0
  455. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__string__.kt +80 -0
  456. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/GridTile.kt +24 -0
  457. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HybridAudioBrowserSpec.kt +1 -1
  458. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSOptions.kt +6 -3
  459. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageShape.kt +23 -0
  460. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +8 -5
  461. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroAndroidUpdateOptions.kt +3 -3
  462. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroIOSUpdateOptions.kt +6 -3
  463. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
  464. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{NotificationButton.kt → RemoteButton.kt} +3 -3
  465. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteButtonLayout.kt +44 -0
  466. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +12 -15
  467. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{FavoriteConfig.kt → Section.kt} +15 -6
  468. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SectionStyle.kt +59 -0
  469. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StyleDisplay.kt +23 -0
  470. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +6 -12
  471. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +35 -5
  472. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/{Variant_NullType_NotificationButtonLayout.kt → Variant_NullType_RemoteButtonLayout.kt} +9 -9
  473. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.cpp +9 -0
  474. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +244 -133
  475. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +31 -16
  476. package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +33 -18
  477. package/nitrogen/generated/ios/swift/AndroidOptions.swift +12 -12
  478. package/nitrogen/generated/ios/swift/ArtworkRendering.swift +40 -0
  479. package/nitrogen/generated/ios/swift/CarPlayPlayingIndicatorLocation.swift +40 -0
  480. package/nitrogen/generated/ios/swift/CardImage.swift +40 -0
  481. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__string__.swift +54 -0
  482. package/nitrogen/generated/ios/swift/GridTile.swift +44 -0
  483. package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec.swift +1 -1
  484. package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec_cxx.swift +2 -2
  485. package/nitrogen/generated/ios/swift/IOSOptions.swift +7 -2
  486. package/nitrogen/generated/ios/swift/ImageShape.swift +40 -0
  487. package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +52 -5
  488. package/nitrogen/generated/ios/swift/NitroAndroidUpdateOptions.swift +12 -12
  489. package/nitrogen/generated/ios/swift/NitroIOSUpdateOptions.swift +12 -1
  490. package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +8 -27
  491. package/nitrogen/generated/ios/swift/{NotificationButton.swift → RemoteButton.swift} +6 -6
  492. package/nitrogen/generated/ios/swift/RemoteButtonLayout.swift +57 -0
  493. package/nitrogen/generated/ios/swift/ResolvedTrack.swift +62 -73
  494. package/nitrogen/generated/ios/swift/Section.swift +82 -0
  495. package/nitrogen/generated/ios/swift/SectionStyle.swift +133 -0
  496. package/nitrogen/generated/ios/swift/StyleDisplay.swift +40 -0
  497. package/nitrogen/generated/ios/swift/Track.swift +28 -63
  498. package/nitrogen/generated/ios/swift/TrackStyle.swift +86 -22
  499. package/nitrogen/generated/ios/swift/{Variant_NullType_NotificationButtonLayout.swift → Variant_NullType_RemoteButtonLayout.swift} +3 -3
  500. package/nitrogen/generated/shared/c++/AndroidOptions.hpp +8 -8
  501. package/nitrogen/generated/shared/c++/{FavoritesMatchMode.hpp → ArtworkRendering.hpp} +17 -17
  502. package/nitrogen/generated/shared/c++/CarPlayPlayingIndicatorLocation.hpp +76 -0
  503. package/nitrogen/generated/shared/c++/CardImage.hpp +76 -0
  504. package/nitrogen/generated/shared/c++/GridTile.hpp +80 -0
  505. package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.cpp +1 -1
  506. package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.hpp +1 -1
  507. package/nitrogen/generated/shared/c++/IOSOptions.hpp +9 -2
  508. package/nitrogen/generated/shared/c++/ImageShape.hpp +76 -0
  509. package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +10 -6
  510. package/nitrogen/generated/shared/c++/NitroAndroidUpdateOptions.hpp +8 -8
  511. package/nitrogen/generated/shared/c++/NitroIOSUpdateOptions.hpp +9 -2
  512. package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +6 -9
  513. package/nitrogen/generated/shared/c++/{NotificationButton.hpp → RemoteButton.hpp} +19 -19
  514. package/nitrogen/generated/shared/c++/RemoteButtonLayout.hpp +94 -0
  515. package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +33 -37
  516. package/nitrogen/generated/shared/c++/Section.hpp +102 -0
  517. package/nitrogen/generated/shared/c++/SectionStyle.hpp +126 -0
  518. package/nitrogen/generated/shared/c++/StyleDisplay.hpp +76 -0
  519. package/nitrogen/generated/shared/c++/Track.hpp +18 -30
  520. package/nitrogen/generated/shared/c++/TrackStyle.hpp +73 -34
  521. package/package.json +24 -11
  522. package/src/AudioBrowser.ts +2 -1
  523. package/src/CLAUDE.md +52 -0
  524. package/src/features/battery.test.ts +79 -0
  525. package/src/features/browser-config.test.ts +21 -6
  526. package/src/features/browser-config.ts +12 -8
  527. package/src/features/browser.test.ts +1 -1
  528. package/src/features/browser.ts +11 -3
  529. package/src/features/carConnection.ts +1 -1
  530. package/src/features/equalizer.ts +1 -1
  531. package/src/features/errors.ts +3 -3
  532. package/src/features/favorites.ts +14 -11
  533. package/src/features/gate.ts +16 -1
  534. package/src/features/hook-wiring.test.ts +302 -0
  535. package/src/features/metadata.ts +20 -3
  536. package/src/features/network.ts +1 -1
  537. package/src/features/nowPlaying.ts +1 -1
  538. package/src/features/output.ts +1 -1
  539. package/src/features/playback/controls.ts +4 -2
  540. package/src/features/playback/playWhenReady.ts +1 -1
  541. package/src/features/playback/playing.ts +1 -1
  542. package/src/features/playback/progress.test.ts +169 -0
  543. package/src/features/playback/progress.ts +3 -2
  544. package/src/features/playback/rate.ts +8 -1
  545. package/src/features/playback/state.ts +3 -4
  546. package/src/features/playback/trackPlaybackTime.test.ts +16 -6
  547. package/src/features/playback/trackPlaybackTime.ts +1 -6
  548. package/src/features/playback/volume.ts +1 -1
  549. package/src/features/player/options.ts +126 -76
  550. package/src/features/player/setup.test.ts +24 -7
  551. package/src/features/player/setup.ts +22 -10
  552. package/src/features/player/validateOptions.ts +21 -0
  553. package/src/features/queue/activeTrack.ts +15 -4
  554. package/src/features/queue/queue.ts +13 -6
  555. package/src/features/queue/repeatMode.ts +1 -1
  556. package/src/features/queue/shuffle.ts +1 -1
  557. package/src/features/remoteControls.ts +13 -92
  558. package/src/features/sleepTimer.test.ts +172 -0
  559. package/src/features/sleepTimer.ts +9 -1
  560. package/src/nitro-stub-drift.test.ts +277 -0
  561. package/src/public-surface.test.ts +147 -0
  562. package/src/specs/audio-browser.nitro.ts +5 -4
  563. package/src/style-resolution.test.ts +210 -0
  564. package/src/test-utils/reactNativeStub.ts +60 -0
  565. package/src/types/browser-native.ts +7 -3
  566. package/src/types/browser-nodes.ts +396 -134
  567. package/src/types/browser.ts +85 -59
  568. package/src/utils/LazyNativeEmitter.ts +28 -15
  569. package/src/utils/NativeUpdatedValue.ts +29 -13
  570. package/src/utils/getTrackIdentity.ts +20 -0
  571. package/src/utils/useDebug.test.ts +182 -0
  572. package/src/utils/useNativeUpdatedValue.test.ts +103 -0
  573. package/src/utils/useNativeValueRefreshedBy.ts +38 -0
  574. package/src/web/NativeAudioBrowser.playWhenReady.test.ts +232 -2
  575. package/src/web/NativeAudioBrowser.ts +239 -82
  576. package/src/web/TrackPlayer/LoadAttempt.ts +29 -0
  577. package/src/web/TrackPlayer/PlaybackStateMachine.test.ts +60 -13
  578. package/src/web/TrackPlayer/PlaybackStateMachine.ts +22 -6
  579. package/src/web/TrackPlayer/Player.dispatch.test.ts +5 -3
  580. package/src/web/TrackPlayer/Player.load.test.ts +137 -1
  581. package/src/web/TrackPlayer/Player.ts +284 -37
  582. package/src/web/TrackPlayer/QueueManager.test.ts +29 -0
  583. package/src/web/TrackPlayer/QueueManager.ts +14 -0
  584. package/src/web/TrackPlayer/QueuePlayer.ts +33 -14
  585. package/src/web/__tests__/lifecycle.test.ts +345 -0
  586. package/src/web/__tests__/lifecycleHarness.ts +351 -0
  587. package/src/web/__tests__/loadEdgeCases.test.ts +246 -0
  588. package/src/web/__tests__/loadSupersession.test.ts +175 -0
  589. package/src/web/__tests__/retry.test.ts +169 -0
  590. package/src/web/browser/BrowserManager.ts +209 -111
  591. package/src/web/browser/FavoriteManager.test.ts +84 -0
  592. package/src/web/browser/FavoriteManager.ts +28 -23
  593. package/src/web/browser/SearchManager.test.ts +75 -0
  594. package/src/web/browser/SearchManager.ts +25 -28
  595. package/src/web/browser/__tests__/artwork-resolution.test.ts +117 -0
  596. package/src/web/browser/__tests__/layer-resolver.test.ts +35 -0
  597. package/src/web/browser/__tests__/search-artwork.test.ts +46 -0
  598. package/src/web/browser/__tests__/search-navigation.test.ts +76 -0
  599. package/src/web/browser/assertBrowsePageShape.test.ts +1 -1
  600. package/src/web/browser/assertBrowsePageShape.ts +5 -3
  601. package/src/web/browser/classifyTrackNavigation.test.ts +10 -8
  602. package/src/web/browser/classifyTrackNavigation.ts +9 -9
  603. package/src/web/browser/parseSearchResponse.test.ts +8 -2
  604. package/src/web/browser/sections.test.ts +91 -0
  605. package/src/web/browser/sections.ts +72 -0
  606. package/src/web/http/RequestConfigBuilder.test.ts +241 -1
  607. package/src/web/http/RequestConfigBuilder.ts +140 -33
  608. package/src/web/http/followMediaRedirect.test.ts +289 -0
  609. package/src/web/http/followMediaRedirect.ts +253 -0
  610. package/src/web/player/NowPlayingManager.ts +4 -3
  611. package/src/web/util/BrowserPathHelper.test.ts +52 -0
  612. package/src/web/util/BrowserPathHelper.ts +61 -13
  613. package/website/guide/android-auto.md +114 -0
  614. package/website/guide/android-certificates.md +409 -0
  615. package/website/guide/artwork.md +255 -0
  616. package/website/guide/audio-output.md +135 -0
  617. package/website/guide/automotive.md +86 -0
  618. package/website/guide/basic-usage.md +151 -0
  619. package/website/guide/battery.md +115 -0
  620. package/website/guide/browser.md +581 -0
  621. package/website/guide/carplay.md +620 -0
  622. package/website/guide/configuration.md +173 -0
  623. package/website/guide/equalizer.md +231 -0
  624. package/website/guide/errors.md +310 -0
  625. package/website/guide/favorites.md +154 -0
  626. package/website/guide/gate.md +143 -0
  627. package/website/guide/getting-started.md +46 -0
  628. package/website/guide/hooks.md +238 -0
  629. package/website/guide/live-streams.md +125 -0
  630. package/website/guide/metadata.md +239 -0
  631. package/website/guide/migrating-from-track-player.md +244 -0
  632. package/website/guide/native-callback-fetch.md +127 -0
  633. package/website/guide/network.md +86 -0
  634. package/website/guide/now-playing.md +175 -0
  635. package/website/guide/playback.md +328 -0
  636. package/website/guide/queue.md +300 -0
  637. package/website/guide/remote-controls.md +256 -0
  638. package/website/guide/search.md +255 -0
  639. package/website/guide/sleep-timer.md +268 -0
  640. package/website/guide/track.md +247 -0
  641. package/ios/CarPlay/ImageRowItem+CarPlay.swift +0 -19
  642. package/ios/Model/MediaURL.swift +0 -67
  643. package/nitrogen/generated/android/c++/JFavoriteConfig.hpp +0 -58
  644. package/nitrogen/generated/android/c++/JImageRowItem.hpp +0 -105
  645. package/nitrogen/generated/android/c++/JNotificationButtonLayout.hpp +0 -94
  646. package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.cpp +0 -26
  647. package/nitrogen/generated/android/c++/JVariant_Boolean_FavoriteConfig.hpp +0 -71
  648. package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.cpp +0 -26
  649. package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.hpp +0 -75
  650. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +0 -68
  651. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButtonLayout.kt +0 -50
  652. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_FavoriteConfig.kt +0 -53
  653. package/nitrogen/generated/ios/swift/FavoriteConfig.swift +0 -29
  654. package/nitrogen/generated/ios/swift/FavoritesMatchMode.swift +0 -40
  655. package/nitrogen/generated/ios/swift/ImageRowItem.swift +0 -195
  656. package/nitrogen/generated/ios/swift/NotificationButtonLayout.swift +0 -92
  657. package/nitrogen/generated/ios/swift/Variant_Bool_FavoriteConfig.swift +0 -18
  658. package/nitrogen/generated/shared/c++/FavoriteConfig.hpp +0 -84
  659. package/nitrogen/generated/shared/c++/ImageRowItem.hpp +0 -129
  660. package/nitrogen/generated/shared/c++/NotificationButtonLayout.hpp +0 -102
@@ -0,0 +1,76 @@
1
+ ///
2
+ /// StyleDisplay.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/NitroHash.hpp>)
11
+ #include <NitroModules/NitroHash.hpp>
12
+ #else
13
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
14
+ #endif
15
+ #if __has_include(<NitroModules/JSIConverter.hpp>)
16
+ #include <NitroModules/JSIConverter.hpp>
17
+ #else
18
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
19
+ #endif
20
+ #if __has_include(<NitroModules/NitroDefines.hpp>)
21
+ #include <NitroModules/NitroDefines.hpp>
22
+ #else
23
+ #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
24
+ #endif
25
+
26
+ namespace margelo::nitro::audiobrowser {
27
+
28
+ /**
29
+ * An enum which can be represented as a JavaScript union (StyleDisplay).
30
+ */
31
+ enum class StyleDisplay {
32
+ LIST SWIFT_NAME(list) = 0,
33
+ GRID SWIFT_NAME(grid) = 1,
34
+ } CLOSED_ENUM;
35
+
36
+ } // namespace margelo::nitro::audiobrowser
37
+
38
+ namespace margelo::nitro {
39
+
40
+ // C++ StyleDisplay <> JS StyleDisplay (union)
41
+ template <>
42
+ struct JSIConverter<margelo::nitro::audiobrowser::StyleDisplay> final {
43
+ static inline margelo::nitro::audiobrowser::StyleDisplay fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
44
+ std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, arg);
45
+ switch (hashString(unionValue.c_str(), unionValue.size())) {
46
+ case hashString("list"): return margelo::nitro::audiobrowser::StyleDisplay::LIST;
47
+ case hashString("grid"): return margelo::nitro::audiobrowser::StyleDisplay::GRID;
48
+ default: [[unlikely]]
49
+ throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum StyleDisplay - invalid value!");
50
+ }
51
+ }
52
+ static inline jsi::Value toJSI(jsi::Runtime& runtime, margelo::nitro::audiobrowser::StyleDisplay arg) {
53
+ switch (arg) {
54
+ case margelo::nitro::audiobrowser::StyleDisplay::LIST: return JSIConverter<std::string>::toJSI(runtime, "list");
55
+ case margelo::nitro::audiobrowser::StyleDisplay::GRID: return JSIConverter<std::string>::toJSI(runtime, "grid");
56
+ default: [[unlikely]]
57
+ throw std::invalid_argument("Cannot convert StyleDisplay to JS - invalid value: "
58
+ + std::to_string(static_cast<int>(arg)) + "!");
59
+ }
60
+ }
61
+ static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
62
+ if (!value.isString()) {
63
+ return false;
64
+ }
65
+ std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, value);
66
+ switch (hashString(unionValue.c_str(), unionValue.size())) {
67
+ case hashString("list"):
68
+ case hashString("grid"):
69
+ return true;
70
+ default:
71
+ return false;
72
+ }
73
+ }
74
+ };
75
+
76
+ } // namespace margelo::nitro
@@ -35,9 +35,7 @@ namespace margelo::nitro::audiobrowser { struct ImageSource; }
35
35
  // Forward declaration of `TrackRequest` to properly resolve imports.
36
36
  namespace margelo::nitro::audiobrowser { struct TrackRequest; }
37
37
  // Forward declaration of `TrackStyle` to properly resolve imports.
38
- namespace margelo::nitro::audiobrowser { enum class TrackStyle; }
39
- // Forward declaration of `ImageRowItem` to properly resolve imports.
40
- namespace margelo::nitro::audiobrowser { struct ImageRowItem; }
38
+ namespace margelo::nitro::audiobrowser { struct TrackStyle; }
41
39
 
42
40
  #include <string>
43
41
  #include <optional>
@@ -46,8 +44,6 @@ namespace margelo::nitro::audiobrowser { struct ImageRowItem; }
46
44
  #include "ImageSource.hpp"
47
45
  #include "TrackRequest.hpp"
48
46
  #include "TrackStyle.hpp"
49
- #include "ImageRowItem.hpp"
50
- #include <vector>
51
47
 
52
48
  namespace margelo::nitro::audiobrowser {
53
49
 
@@ -57,30 +53,28 @@ namespace margelo::nitro::audiobrowser {
57
53
  struct Track final {
58
54
  public:
59
55
  std::optional<std::string> id SWIFT_PRIVATE;
60
- std::optional<std::string> url SWIFT_PRIVATE;
56
+ std::optional<std::string> path SWIFT_PRIVATE;
61
57
  std::optional<std::string> src SWIFT_PRIVATE;
62
58
  std::optional<std::variant<std::string, ArtworkVariants>> artwork SWIFT_PRIVATE;
63
59
  std::optional<ImageSource> artworkSource SWIFT_PRIVATE;
64
60
  std::optional<TrackRequest> request SWIFT_PRIVATE;
65
- std::optional<bool> artworkCarPlayTinted SWIFT_PRIVATE;
66
61
  std::string title SWIFT_PRIVATE;
67
62
  std::optional<std::string> subtitle SWIFT_PRIVATE;
68
63
  std::optional<std::string> artist SWIFT_PRIVATE;
69
- std::optional<std::string> albumUrl SWIFT_PRIVATE;
64
+ std::optional<std::string> albumPath SWIFT_PRIVATE;
70
65
  std::optional<std::string> album SWIFT_PRIVATE;
71
66
  std::optional<std::string> description SWIFT_PRIVATE;
72
67
  std::optional<std::string> genre SWIFT_PRIVATE;
73
68
  std::optional<double> duration SWIFT_PRIVATE;
74
69
  std::optional<TrackStyle> style SWIFT_PRIVATE;
75
- std::optional<TrackStyle> childrenStyle SWIFT_PRIVATE;
70
+ std::optional<bool> disabled SWIFT_PRIVATE;
76
71
  std::optional<bool> favorited SWIFT_PRIVATE;
77
- std::optional<std::string> groupTitle SWIFT_PRIVATE;
78
72
  std::optional<bool> live SWIFT_PRIVATE;
79
- std::optional<std::vector<ImageRowItem>> imageRow SWIFT_PRIVATE;
73
+ std::optional<std::string> icyCharset SWIFT_PRIVATE;
80
74
 
81
75
  public:
82
76
  Track() = default;
83
- explicit Track(std::optional<std::string> id, std::optional<std::string> url, std::optional<std::string> src, std::optional<std::variant<std::string, ArtworkVariants>> artwork, std::optional<ImageSource> artworkSource, std::optional<TrackRequest> request, std::optional<bool> artworkCarPlayTinted, std::string title, std::optional<std::string> subtitle, std::optional<std::string> artist, std::optional<std::string> albumUrl, std::optional<std::string> album, std::optional<std::string> description, std::optional<std::string> genre, std::optional<double> duration, std::optional<TrackStyle> style, std::optional<TrackStyle> childrenStyle, std::optional<bool> favorited, std::optional<std::string> groupTitle, std::optional<bool> live, std::optional<std::vector<ImageRowItem>> imageRow): id(id), url(url), src(src), artwork(artwork), artworkSource(artworkSource), request(request), artworkCarPlayTinted(artworkCarPlayTinted), title(title), subtitle(subtitle), artist(artist), albumUrl(albumUrl), album(album), description(description), genre(genre), duration(duration), style(style), childrenStyle(childrenStyle), favorited(favorited), groupTitle(groupTitle), live(live), imageRow(imageRow) {}
77
+ explicit Track(std::optional<std::string> id, std::optional<std::string> path, std::optional<std::string> src, std::optional<std::variant<std::string, ArtworkVariants>> artwork, std::optional<ImageSource> artworkSource, std::optional<TrackRequest> request, std::string title, std::optional<std::string> subtitle, std::optional<std::string> artist, std::optional<std::string> albumPath, std::optional<std::string> album, std::optional<std::string> description, std::optional<std::string> genre, std::optional<double> duration, std::optional<TrackStyle> style, std::optional<bool> disabled, std::optional<bool> favorited, std::optional<bool> live, std::optional<std::string> icyCharset): id(id), path(path), src(src), artwork(artwork), artworkSource(artworkSource), request(request), title(title), subtitle(subtitle), artist(artist), albumPath(albumPath), album(album), description(description), genre(genre), duration(duration), style(style), disabled(disabled), favorited(favorited), live(live), icyCharset(icyCharset) {}
84
78
 
85
79
  public:
86
80
  friend bool operator==(const Track& lhs, const Track& rhs) = default;
@@ -97,51 +91,47 @@ namespace margelo::nitro {
97
91
  jsi::Object obj = arg.asObject(runtime);
98
92
  return margelo::nitro::audiobrowser::Track(
99
93
  JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "id"))),
100
- JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "url"))),
94
+ JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "path"))),
101
95
  JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "src"))),
102
96
  JSIConverter<std::optional<std::variant<std::string, margelo::nitro::audiobrowser::ArtworkVariants>>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artwork"))),
103
97
  JSIConverter<std::optional<margelo::nitro::audiobrowser::ImageSource>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artworkSource"))),
104
98
  JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackRequest>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "request"))),
105
- JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artworkCarPlayTinted"))),
106
99
  JSIConverter<std::string>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "title"))),
107
100
  JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "subtitle"))),
108
101
  JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artist"))),
109
- JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "albumUrl"))),
102
+ JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "albumPath"))),
110
103
  JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "album"))),
111
104
  JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "description"))),
112
105
  JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "genre"))),
113
106
  JSIConverter<std::optional<double>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "duration"))),
114
107
  JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackStyle>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "style"))),
115
- JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackStyle>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "childrenStyle"))),
108
+ JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "disabled"))),
116
109
  JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "favorited"))),
117
- JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "groupTitle"))),
118
110
  JSIConverter<std::optional<bool>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "live"))),
119
- JSIConverter<std::optional<std::vector<margelo::nitro::audiobrowser::ImageRowItem>>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "imageRow")))
111
+ JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "icyCharset")))
120
112
  );
121
113
  }
122
114
  static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::audiobrowser::Track& arg) {
123
115
  jsi::Object obj(runtime);
124
116
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "id"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.id));
125
- obj.setProperty(runtime, PropNameIDCache::get(runtime, "url"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.url));
117
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "path"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.path));
126
118
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "src"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.src));
127
119
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "artwork"), JSIConverter<std::optional<std::variant<std::string, margelo::nitro::audiobrowser::ArtworkVariants>>>::toJSI(runtime, arg.artwork));
128
120
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "artworkSource"), JSIConverter<std::optional<margelo::nitro::audiobrowser::ImageSource>>::toJSI(runtime, arg.artworkSource));
129
121
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "request"), JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackRequest>>::toJSI(runtime, arg.request));
130
- obj.setProperty(runtime, PropNameIDCache::get(runtime, "artworkCarPlayTinted"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.artworkCarPlayTinted));
131
122
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "title"), JSIConverter<std::string>::toJSI(runtime, arg.title));
132
123
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "subtitle"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.subtitle));
133
124
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "artist"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.artist));
134
- obj.setProperty(runtime, PropNameIDCache::get(runtime, "albumUrl"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.albumUrl));
125
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "albumPath"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.albumPath));
135
126
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "album"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.album));
136
127
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "description"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.description));
137
128
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "genre"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.genre));
138
129
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "duration"), JSIConverter<std::optional<double>>::toJSI(runtime, arg.duration));
139
130
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "style"), JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackStyle>>::toJSI(runtime, arg.style));
140
- obj.setProperty(runtime, PropNameIDCache::get(runtime, "childrenStyle"), JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackStyle>>::toJSI(runtime, arg.childrenStyle));
131
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "disabled"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.disabled));
141
132
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "favorited"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.favorited));
142
- obj.setProperty(runtime, PropNameIDCache::get(runtime, "groupTitle"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.groupTitle));
143
133
  obj.setProperty(runtime, PropNameIDCache::get(runtime, "live"), JSIConverter<std::optional<bool>>::toJSI(runtime, arg.live));
144
- obj.setProperty(runtime, PropNameIDCache::get(runtime, "imageRow"), JSIConverter<std::optional<std::vector<margelo::nitro::audiobrowser::ImageRowItem>>>::toJSI(runtime, arg.imageRow));
134
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "icyCharset"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.icyCharset));
145
135
  return obj;
146
136
  }
147
137
  static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
@@ -153,26 +143,24 @@ namespace margelo::nitro {
153
143
  return false;
154
144
  }
155
145
  if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "id")))) return false;
156
- if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "url")))) return false;
146
+ if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "path")))) return false;
157
147
  if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "src")))) return false;
158
148
  if (!JSIConverter<std::optional<std::variant<std::string, margelo::nitro::audiobrowser::ArtworkVariants>>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artwork")))) return false;
159
149
  if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::ImageSource>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artworkSource")))) return false;
160
150
  if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackRequest>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "request")))) return false;
161
- if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artworkCarPlayTinted")))) return false;
162
151
  if (!JSIConverter<std::string>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "title")))) return false;
163
152
  if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "subtitle")))) return false;
164
153
  if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artist")))) return false;
165
- if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "albumUrl")))) return false;
154
+ if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "albumPath")))) return false;
166
155
  if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "album")))) return false;
167
156
  if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "description")))) return false;
168
157
  if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "genre")))) return false;
169
158
  if (!JSIConverter<std::optional<double>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "duration")))) return false;
170
159
  if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackStyle>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "style")))) return false;
171
- if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::TrackStyle>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "childrenStyle")))) return false;
160
+ if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "disabled")))) return false;
172
161
  if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "favorited")))) return false;
173
- if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "groupTitle")))) return false;
174
162
  if (!JSIConverter<std::optional<bool>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "live")))) return false;
175
- if (!JSIConverter<std::optional<std::vector<margelo::nitro::audiobrowser::ImageRowItem>>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "imageRow")))) return false;
163
+ if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "icyCharset")))) return false;
176
164
  return true;
177
165
  }
178
166
  };
@@ -7,11 +7,6 @@
7
7
 
8
8
  #pragma once
9
9
 
10
- #if __has_include(<NitroModules/NitroHash.hpp>)
11
- #include <NitroModules/NitroHash.hpp>
12
- #else
13
- #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
14
- #endif
15
10
  #if __has_include(<NitroModules/JSIConverter.hpp>)
16
11
  #include <NitroModules/JSIConverter.hpp>
17
12
  #else
@@ -22,54 +17,98 @@
22
17
  #else
23
18
  #error NitroModules cannot be found! Are you sure you installed NitroModules properly?
24
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 `StyleDisplay` to properly resolve imports.
32
+ namespace margelo::nitro::audiobrowser { enum class StyleDisplay; }
33
+ // Forward declaration of `ArtworkRendering` to properly resolve imports.
34
+ namespace margelo::nitro::audiobrowser { enum class ArtworkRendering; }
35
+ // Forward declaration of `ImageShape` to properly resolve imports.
36
+ namespace margelo::nitro::audiobrowser { enum class ImageShape; }
37
+ // Forward declaration of `CardImage` to properly resolve imports.
38
+ namespace margelo::nitro::audiobrowser { enum class CardImage; }
39
+
40
+ #include "StyleDisplay.hpp"
41
+ #include <optional>
42
+ #include "ArtworkRendering.hpp"
43
+ #include "ImageShape.hpp"
44
+ #include <string>
45
+ #include "CardImage.hpp"
25
46
 
26
47
  namespace margelo::nitro::audiobrowser {
27
48
 
28
49
  /**
29
- * An enum which can be represented as a JavaScript union (TrackStyle).
50
+ * A struct which can be represented as a JavaScript object (TrackStyle).
30
51
  */
31
- enum class TrackStyle {
32
- LIST SWIFT_NAME(list) = 0,
33
- GRID SWIFT_NAME(grid) = 1,
34
- } CLOSED_ENUM;
52
+ struct TrackStyle final {
53
+ public:
54
+ std::optional<StyleDisplay> display SWIFT_PRIVATE;
55
+ std::optional<ArtworkRendering> artworkRendering SWIFT_PRIVATE;
56
+ std::optional<ImageShape> imageShape SWIFT_PRIVATE;
57
+ std::optional<std::string> accessorySymbol SWIFT_PRIVATE;
58
+ std::optional<std::string> cardTint SWIFT_PRIVATE;
59
+ std::optional<CardImage> cardImage SWIFT_PRIVATE;
60
+
61
+ public:
62
+ TrackStyle() = default;
63
+ explicit TrackStyle(std::optional<StyleDisplay> display, std::optional<ArtworkRendering> artworkRendering, std::optional<ImageShape> imageShape, std::optional<std::string> accessorySymbol, std::optional<std::string> cardTint, std::optional<CardImage> cardImage): display(display), artworkRendering(artworkRendering), imageShape(imageShape), accessorySymbol(accessorySymbol), cardTint(cardTint), cardImage(cardImage) {}
64
+
65
+ public:
66
+ friend bool operator==(const TrackStyle& lhs, const TrackStyle& rhs) = default;
67
+ };
35
68
 
36
69
  } // namespace margelo::nitro::audiobrowser
37
70
 
38
71
  namespace margelo::nitro {
39
72
 
40
- // C++ TrackStyle <> JS TrackStyle (union)
73
+ // C++ TrackStyle <> JS TrackStyle (object)
41
74
  template <>
42
75
  struct JSIConverter<margelo::nitro::audiobrowser::TrackStyle> final {
43
76
  static inline margelo::nitro::audiobrowser::TrackStyle fromJSI(jsi::Runtime& runtime, const jsi::Value& arg) {
44
- std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, arg);
45
- switch (hashString(unionValue.c_str(), unionValue.size())) {
46
- case hashString("list"): return margelo::nitro::audiobrowser::TrackStyle::LIST;
47
- case hashString("grid"): return margelo::nitro::audiobrowser::TrackStyle::GRID;
48
- default: [[unlikely]]
49
- throw std::invalid_argument("Cannot convert \"" + unionValue + "\" to enum TrackStyle - invalid value!");
50
- }
77
+ jsi::Object obj = arg.asObject(runtime);
78
+ return margelo::nitro::audiobrowser::TrackStyle(
79
+ JSIConverter<std::optional<margelo::nitro::audiobrowser::StyleDisplay>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "display"))),
80
+ JSIConverter<std::optional<margelo::nitro::audiobrowser::ArtworkRendering>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artworkRendering"))),
81
+ JSIConverter<std::optional<margelo::nitro::audiobrowser::ImageShape>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "imageShape"))),
82
+ JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "accessorySymbol"))),
83
+ JSIConverter<std::optional<std::string>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "cardTint"))),
84
+ JSIConverter<std::optional<margelo::nitro::audiobrowser::CardImage>>::fromJSI(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "cardImage")))
85
+ );
51
86
  }
52
- static inline jsi::Value toJSI(jsi::Runtime& runtime, margelo::nitro::audiobrowser::TrackStyle arg) {
53
- switch (arg) {
54
- case margelo::nitro::audiobrowser::TrackStyle::LIST: return JSIConverter<std::string>::toJSI(runtime, "list");
55
- case margelo::nitro::audiobrowser::TrackStyle::GRID: return JSIConverter<std::string>::toJSI(runtime, "grid");
56
- default: [[unlikely]]
57
- throw std::invalid_argument("Cannot convert TrackStyle to JS - invalid value: "
58
- + std::to_string(static_cast<int>(arg)) + "!");
59
- }
87
+ static inline jsi::Value toJSI(jsi::Runtime& runtime, const margelo::nitro::audiobrowser::TrackStyle& arg) {
88
+ jsi::Object obj(runtime);
89
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "display"), JSIConverter<std::optional<margelo::nitro::audiobrowser::StyleDisplay>>::toJSI(runtime, arg.display));
90
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "artworkRendering"), JSIConverter<std::optional<margelo::nitro::audiobrowser::ArtworkRendering>>::toJSI(runtime, arg.artworkRendering));
91
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "imageShape"), JSIConverter<std::optional<margelo::nitro::audiobrowser::ImageShape>>::toJSI(runtime, arg.imageShape));
92
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "accessorySymbol"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.accessorySymbol));
93
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "cardTint"), JSIConverter<std::optional<std::string>>::toJSI(runtime, arg.cardTint));
94
+ obj.setProperty(runtime, PropNameIDCache::get(runtime, "cardImage"), JSIConverter<std::optional<margelo::nitro::audiobrowser::CardImage>>::toJSI(runtime, arg.cardImage));
95
+ return obj;
60
96
  }
61
97
  static inline bool canConvert(jsi::Runtime& runtime, const jsi::Value& value) {
62
- if (!value.isString()) {
98
+ if (!value.isObject()) {
63
99
  return false;
64
100
  }
65
- std::string unionValue = JSIConverter<std::string>::fromJSI(runtime, value);
66
- switch (hashString(unionValue.c_str(), unionValue.size())) {
67
- case hashString("list"):
68
- case hashString("grid"):
69
- return true;
70
- default:
71
- return false;
101
+ jsi::Object obj = value.getObject(runtime);
102
+ if (!nitro::isPlainObject(runtime, obj)) {
103
+ return false;
72
104
  }
105
+ if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::StyleDisplay>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "display")))) return false;
106
+ if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::ArtworkRendering>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "artworkRendering")))) return false;
107
+ if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::ImageShape>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "imageShape")))) return false;
108
+ if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "accessorySymbol")))) return false;
109
+ if (!JSIConverter<std::optional<std::string>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "cardTint")))) return false;
110
+ if (!JSIConverter<std::optional<margelo::nitro::audiobrowser::CardImage>>::canConvert(runtime, obj.getProperty(runtime, PropNameIDCache::get(runtime, "cardImage")))) return false;
111
+ return true;
73
112
  }
74
113
  };
75
114
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "react-native-audio-browser",
3
- "version": "0.2.0-next.2",
3
+ "version": "0.2.0-next.20",
4
4
  "description": "react-native-audio-browser is a react native package built with Nitro",
5
5
  "keywords": [
6
6
  "react-native",
@@ -31,6 +31,7 @@
31
31
  "ios/**/*.mm",
32
32
  "ios/**/*.cpp",
33
33
  "ios/**/*.swift",
34
+ "website/guide",
34
35
  "*.podspec",
35
36
  "README.md"
36
37
  ],
@@ -45,21 +46,28 @@
45
46
  },
46
47
  "scripts": {
47
48
  "android:format": "yarn workspace example-native android:format",
49
+ "android:format:check": "yarn workspace example-native android:format:check",
50
+ "android:gradle-stop": "yarn workspace example-native android:gradle-stop",
48
51
  "android:ide": "yarn workspace example-native android:ide",
49
52
  "android:logs": "react-native log-android",
50
53
  "android:test": "yarn workspace example-native android:test",
54
+ "android:types": "yarn workspace example-native android:types",
51
55
  "build": "yarn prepare",
52
56
  "clean": "del-cli android/build example/android/build example/android/app/build example/ios/build lib",
53
57
  "codegen": "node codegen/index.js --logLevel=\"debug\" && node post-script.cjs && node codegen/strip-struct-equality.cjs && yarn build",
54
- "prepare": "bob build",
58
+ "prepare": "bob build && echo '{\"type\":\"commonjs\"}' > lib/typescript/package.json && yarn hooks:install",
59
+ "hooks:install": "git config core.hooksPath .githooks || exit 0",
55
60
  "example": "yarn workspace example-native",
56
- "ci:format": "oxfmt --check src",
61
+ "ci:android": "yarn android:format:check && yarn android:types && yarn android:test",
62
+ "ci:format": "oxfmt --check --ignore-path .gitignore --ignore-path .oxfmtignore .",
63
+ "ci:format:ios": "scripts/swiftformat.sh --lint ios",
64
+ "ci:ios": "yarn ci:format:ios && yarn ios:test",
57
65
  "ci:lint": "oxlint --type-aware src",
58
- "format": "oxfmt --write",
59
- "ios:format": "swiftformat ios",
66
+ "format": "oxfmt --write --ignore-path .gitignore --ignore-path .oxfmtignore .",
67
+ "ios:format": "scripts/swiftformat.sh ios",
60
68
  "ios:ide": "yarn workspace example-native ios:ide",
61
69
  "ios:rebuild": "yarn workspace example-native ios:rebuild",
62
- "ios:test": "swift test",
70
+ "ios:test": "swift test --disable-sandbox",
63
71
  "lint": "oxlint --fix",
64
72
  "release": "semantic-release",
65
73
  "test": "vitest run",
@@ -69,19 +77,24 @@
69
77
  "@react-native-community/cli": "15.0.0-alpha.2",
70
78
  "@semantic-release/changelog": "^6.0.3",
71
79
  "@semantic-release/git": "^10.0.1",
80
+ "@testing-library/dom": "^10.4.1",
81
+ "@testing-library/react": "^16.3.2",
72
82
  "@types/node": "^22",
73
- "@types/react": "19.1.1",
83
+ "@types/react": "19.2.3",
84
+ "@types/react-dom": "^19.2.0",
74
85
  "conventional-changelog-conventionalcommits": "^9.3.0",
75
86
  "del-cli": "^5.1.0",
76
- "nitrogen": "0.35.0",
87
+ "happy-dom": "^20.11.2",
88
+ "nitrogen": "0.35.10",
77
89
  "oxfmt": "^0.27.0",
78
90
  "oxlint": "^1.42.0",
79
91
  "oxlint-tsgolint": "^0.11.2",
80
- "react": "19.1.1",
81
- "react-native": "0.83.0",
92
+ "react": "19.2.3",
93
+ "react-dom": "19.2.3",
94
+ "react-native": "0.86.2",
82
95
  "react-native-builder-bob": "^0.37.0",
83
96
  "react-native-monorepo-config": "^0.3.1",
84
- "react-native-nitro-modules": "0.35.0",
97
+ "react-native-nitro-modules": "0.35.10",
85
98
  "semantic-release": "^25.0.3",
86
99
  "shaka-player": "^4.15.4",
87
100
  "typescript": "^7.0.2",
@@ -1,4 +1,5 @@
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
+ export * from './utils/getTrackIdentity'
4
5
  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
+ })