@5stones/react-native-audio-browser 0.1.6 → 0.3.0

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 (593) hide show
  1. package/AudioBrowser.podspec +3 -1
  2. package/android/src/main/cpp/cpp-adapter.cpp +4 -1
  3. package/android/src/main/java/com/audiobrowser/AudioBrowser.kt +15 -9
  4. package/android/src/main/java/com/audiobrowser/Service.kt +0 -2
  5. package/android/src/main/java/com/audiobrowser/browser/BrowserManager.kt +5 -0
  6. package/android/src/main/java/com/audiobrowser/browser/JsonModels.kt +31 -0
  7. package/android/src/main/java/com/audiobrowser/browser/SimpleRouter.kt +10 -6
  8. package/android/src/main/java/com/audiobrowser/browser/TrackLoadHandler.kt +45 -0
  9. package/android/src/main/java/com/audiobrowser/player/MediaSessionCallback.kt +39 -17
  10. package/android/src/main/java/com/audiobrowser/player/PlaybackStateStore.kt +1 -0
  11. package/android/src/main/java/com/audiobrowser/player/Player.kt +1 -0
  12. package/android/src/main/java/com/audiobrowser/player/TransformingDataSource.kt +33 -11
  13. package/android/src/test/java/com/audiobrowser/browser/SimpleRouterTest.kt +104 -95
  14. package/ios/Browser/BrowserConfig.swift +31 -5
  15. package/ios/Browser/BrowserManager.swift +98 -23
  16. package/ios/Browser/JsonModels.swift +37 -0
  17. package/ios/CarPlay/CarPlayController.swift +256 -88
  18. package/ios/CarPlay/RNABAudioBrowser.h +23 -0
  19. package/ios/CarPlay/RNABAudioBrowser.m +22 -0
  20. package/ios/CarPlay/RNABMediaIntentHandler.swift +60 -0
  21. package/ios/Extension/ChapterMetadata+AVFoundation.swift +1 -1
  22. package/ios/Extension/CxxVectorConformances.swift +20 -0
  23. package/ios/Extension/TimedMetadata+AVFoundation.swift +5 -5
  24. package/ios/Extension/Track+AVPlayer.swift +5 -6
  25. package/ios/Extension/TrackMetadata+AVFoundation.swift +1 -1
  26. package/ios/HybridAudioBrowser.swift +126 -35
  27. package/ios/Model/MediaURL.swift +2 -1
  28. package/ios/Player/PlayingStateManager.swift +1 -0
  29. package/ios/Player/RetryManager.swift +26 -65
  30. package/ios/Player/SleepTimerManager.swift +6 -8
  31. package/ios/RemoteCommand/RemoteCommandController.swift +6 -0
  32. package/ios/Tests/SimpleRouterTests.swift +139 -0
  33. package/ios/TrackPlayer.swift +71 -53
  34. package/ios/Util/NetworkMonitor.swift +3 -6
  35. package/ios/Util/SFSymbolRenderer.swift +142 -0
  36. package/lib/commonjs/features/browser.js +1 -0
  37. package/lib/commonjs/features/browser.js.map +1 -1
  38. package/lib/commonjs/web/NativeAudioBrowser.js +32 -7
  39. package/lib/commonjs/web/NativeAudioBrowser.js.map +1 -1
  40. package/lib/commonjs/web/SimpleRouter.js +4 -3
  41. package/lib/commonjs/web/SimpleRouter.js.map +1 -1
  42. package/lib/commonjs/web/SimpleRouter.test.js +174 -0
  43. package/lib/commonjs/web/SimpleRouter.test.js.map +1 -0
  44. package/lib/module/features/browser.js +1 -0
  45. package/lib/module/features/browser.js.map +1 -1
  46. package/lib/module/web/NativeAudioBrowser.js +32 -7
  47. package/lib/module/web/NativeAudioBrowser.js.map +1 -1
  48. package/lib/module/web/SimpleRouter.js +4 -3
  49. package/lib/module/web/SimpleRouter.js.map +1 -1
  50. package/lib/module/web/SimpleRouter.test.js +174 -0
  51. package/lib/module/web/SimpleRouter.test.js.map +1 -0
  52. package/lib/typescript/src/features/browser.d.ts.map +1 -1
  53. package/lib/typescript/src/types/browser-native.d.ts +2 -1
  54. package/lib/typescript/src/types/browser-native.d.ts.map +1 -1
  55. package/lib/typescript/src/types/browser-nodes.d.ts +46 -1
  56. package/lib/typescript/src/types/browser-nodes.d.ts.map +1 -1
  57. package/lib/typescript/src/types/browser.d.ts +32 -0
  58. package/lib/typescript/src/types/browser.d.ts.map +1 -1
  59. package/lib/typescript/src/web/NativeAudioBrowser.d.ts +7 -0
  60. package/lib/typescript/src/web/NativeAudioBrowser.d.ts.map +1 -1
  61. package/lib/typescript/src/web/SimpleRouter.d.ts.map +1 -1
  62. package/lib/typescript/src/web/SimpleRouter.test.d.ts +2 -0
  63. package/lib/typescript/src/web/SimpleRouter.test.d.ts.map +1 -0
  64. package/nitrogen/generated/android/AudioBrowser+autolinking.cmake +1 -1
  65. package/nitrogen/generated/android/AudioBrowser+autolinking.gradle +1 -1
  66. package/nitrogen/generated/android/AudioBrowserOnLoad.cpp +67 -55
  67. package/nitrogen/generated/android/AudioBrowserOnLoad.hpp +14 -5
  68. package/nitrogen/generated/android/c++/JAndroidAudioContentType.hpp +6 -7
  69. package/nitrogen/generated/android/c++/JAndroidAudioOffloadSettings.hpp +1 -1
  70. package/nitrogen/generated/android/c++/JAndroidOptions.hpp +1 -1
  71. package/nitrogen/generated/android/c++/JAndroidPlayerWakeMode.hpp +4 -5
  72. package/nitrogen/generated/android/c++/JAndroidUpdateOptions.hpp +1 -1
  73. package/nitrogen/generated/android/c++/JAppKilledPlaybackBehavior.hpp +4 -5
  74. package/nitrogen/generated/android/c++/JArtworkRequestConfig.hpp +4 -1
  75. package/nitrogen/generated/android/c++/JBatteryOptimizationStatus.hpp +4 -5
  76. package/nitrogen/generated/android/c++/JBatteryOptimizationStatusChangedEvent.hpp +1 -1
  77. package/nitrogen/generated/android/c++/JBatteryWarningPendingChangedEvent.hpp +1 -1
  78. package/nitrogen/generated/android/c++/JBrowseError.hpp +1 -1
  79. package/nitrogen/generated/android/c++/JBrowseResult.cpp +1 -1
  80. package/nitrogen/generated/android/c++/JBrowseResult.hpp +7 -3
  81. package/nitrogen/generated/android/c++/JBrowserSourceCallbackParam.hpp +1 -1
  82. package/nitrogen/generated/android/c++/JCarPlayNowPlayingButton.hpp +5 -6
  83. package/nitrogen/generated/android/c++/JCarPlaySiriListButtonPosition.hpp +58 -0
  84. package/nitrogen/generated/android/c++/JChapterMetadata.hpp +1 -1
  85. package/nitrogen/generated/android/c++/JEqualizerSettings.hpp +1 -1
  86. package/nitrogen/generated/android/c++/JFavoriteChangedEvent.hpp +4 -1
  87. package/nitrogen/generated/android/c++/JFormatNavigationErrorParams.hpp +1 -1
  88. package/nitrogen/generated/android/c++/JFormattedNavigationError.hpp +1 -1
  89. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.hpp +1 -1
  90. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.hpp +1 -1
  91. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____RequestConfig_std__optional_std__unordered_map_std__string__std__string__.hpp +1 -1
  92. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.hpp +4 -1
  93. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.hpp +5 -1
  94. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.hpp +3 -1
  95. package/nitrogen/generated/android/c++/JFunc_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.hpp +139 -0
  96. package/nitrogen/generated/android/c++/JFunc_void.hpp +1 -1
  97. package/nitrogen/generated/android/c++/JFunc_void_BatteryOptimizationStatusChangedEvent.hpp +1 -1
  98. package/nitrogen/generated/android/c++/JFunc_void_BatteryWarningPendingChangedEvent.hpp +1 -1
  99. package/nitrogen/generated/android/c++/JFunc_void_EqualizerSettings.hpp +1 -1
  100. package/nitrogen/generated/android/c++/JFunc_void_FavoriteChangedEvent.hpp +4 -1
  101. package/nitrogen/generated/android/c++/JFunc_void_IosOutput.hpp +1 -1
  102. package/nitrogen/generated/android/c++/JFunc_void_NavigationErrorEvent.hpp +1 -1
  103. package/nitrogen/generated/android/c++/JFunc_void_NowPlayingMetadata.hpp +1 -1
  104. package/nitrogen/generated/android/c++/JFunc_void_Options.hpp +1 -1
  105. package/nitrogen/generated/android/c++/JFunc_void_Playback.hpp +1 -1
  106. package/nitrogen/generated/android/c++/JFunc_void_PlaybackActiveTrackChangedEvent.hpp +4 -1
  107. package/nitrogen/generated/android/c++/JFunc_void_PlaybackErrorEvent.hpp +1 -1
  108. package/nitrogen/generated/android/c++/JFunc_void_PlaybackPlayWhenReadyChangedEvent.hpp +1 -1
  109. package/nitrogen/generated/android/c++/JFunc_void_PlaybackProgressUpdatedEvent.hpp +1 -1
  110. package/nitrogen/generated/android/c++/JFunc_void_PlaybackQueueEndedEvent.hpp +1 -1
  111. package/nitrogen/generated/android/c++/JFunc_void_PlayingState.hpp +1 -1
  112. package/nitrogen/generated/android/c++/JFunc_void_RemoteJumpBackwardEvent.hpp +1 -1
  113. package/nitrogen/generated/android/c++/JFunc_void_RemoteJumpForwardEvent.hpp +1 -1
  114. package/nitrogen/generated/android/c++/JFunc_void_RemotePlayIdEvent.hpp +1 -1
  115. package/nitrogen/generated/android/c++/JFunc_void_RemotePlaySearchEvent.hpp +1 -1
  116. package/nitrogen/generated/android/c++/JFunc_void_RemoteSeekEvent.hpp +1 -1
  117. package/nitrogen/generated/android/c++/JFunc_void_RemoteSetRatingEvent.hpp +1 -1
  118. package/nitrogen/generated/android/c++/JFunc_void_RemoteSkipEvent.hpp +1 -1
  119. package/nitrogen/generated/android/c++/JFunc_void_RepeatModeChangedEvent.hpp +1 -1
  120. package/nitrogen/generated/android/c++/JFunc_void_TimedMetadata.hpp +1 -1
  121. package/nitrogen/generated/android/c++/JFunc_void_TrackMetadata.hpp +1 -1
  122. package/nitrogen/generated/android/c++/JFunc_void_bool.hpp +1 -1
  123. package/nitrogen/generated/android/c++/JFunc_void_double.hpp +1 -1
  124. package/nitrogen/generated/android/c++/JFunc_void_std__optional_FormattedNavigationError_.hpp +1 -1
  125. package/nitrogen/generated/android/c++/JFunc_void_std__optional_ResolvedTrack_.hpp +5 -1
  126. package/nitrogen/generated/android/c++/JFunc_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.hpp +1 -1
  127. package/nitrogen/generated/android/c++/JFunc_void_std__string.hpp +1 -1
  128. package/nitrogen/generated/android/c++/JFunc_void_std__vector_ChapterMetadata_.hpp +1 -1
  129. package/nitrogen/generated/android/c++/JFunc_void_std__vector_Track_.hpp +3 -1
  130. package/nitrogen/generated/android/c++/JHeartRating.hpp +1 -1
  131. package/nitrogen/generated/android/c++/JHttpMethod.hpp +8 -9
  132. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.cpp +230 -206
  133. package/nitrogen/generated/android/c++/JHybridAudioBrowserSpec.hpp +20 -22
  134. package/nitrogen/generated/android/c++/JIOSCategory.hpp +7 -8
  135. package/nitrogen/generated/android/c++/JIOSCategoryMode.hpp +10 -11
  136. package/nitrogen/generated/android/c++/JIOSCategoryOptions.hpp +8 -9
  137. package/nitrogen/generated/android/c++/JIOSCategoryPolicy.hpp +4 -5
  138. package/nitrogen/generated/android/c++/JImageContext.hpp +1 -1
  139. package/nitrogen/generated/android/c++/JImageQueryParams.hpp +1 -1
  140. package/nitrogen/generated/android/c++/JImageRowItem.hpp +75 -0
  141. package/nitrogen/generated/android/c++/JImageSource.hpp +1 -1
  142. package/nitrogen/generated/android/c++/JIosOutput.hpp +1 -1
  143. package/nitrogen/generated/android/c++/JIosOutputType.hpp +12 -13
  144. package/nitrogen/generated/android/c++/JMediaRequestConfig.hpp +4 -1
  145. package/nitrogen/generated/android/c++/JMediaTransformParams.hpp +1 -1
  146. package/nitrogen/generated/android/c++/JNativeBrowserConfiguration.hpp +22 -2
  147. package/nitrogen/generated/android/c++/JNativeRouteEntry.hpp +5 -1
  148. package/nitrogen/generated/android/c++/JNativeUpdateOptions.hpp +1 -1
  149. package/nitrogen/generated/android/c++/JNavigationError.hpp +1 -1
  150. package/nitrogen/generated/android/c++/JNavigationErrorEvent.hpp +1 -1
  151. package/nitrogen/generated/android/c++/JNavigationErrorType.hpp +6 -7
  152. package/nitrogen/generated/android/c++/JNitroAndroidUpdateOptions.hpp +1 -1
  153. package/nitrogen/generated/android/c++/JNotificationButton.hpp +6 -7
  154. package/nitrogen/generated/android/c++/JNotificationButtonLayout.hpp +1 -1
  155. package/nitrogen/generated/android/c++/JNowPlayingMetadata.hpp +1 -1
  156. package/nitrogen/generated/android/c++/JNowPlayingUpdate.hpp +1 -1
  157. package/nitrogen/generated/android/c++/JOptions.hpp +1 -1
  158. package/nitrogen/generated/android/c++/JPartialAndroidSetupPlayerOptions.hpp +1 -1
  159. package/nitrogen/generated/android/c++/JPartialIOSSetupPlayerOptions.hpp +1 -1
  160. package/nitrogen/generated/android/c++/JPartialSetupPlayerOptions.hpp +1 -1
  161. package/nitrogen/generated/android/c++/JPercentageRating.hpp +1 -1
  162. package/nitrogen/generated/android/c++/JPlayback.hpp +1 -1
  163. package/nitrogen/generated/android/c++/JPlaybackActiveTrackChangedEvent.hpp +4 -1
  164. package/nitrogen/generated/android/c++/JPlaybackError.hpp +1 -1
  165. package/nitrogen/generated/android/c++/JPlaybackErrorEvent.hpp +1 -1
  166. package/nitrogen/generated/android/c++/JPlaybackPlayWhenReadyChangedEvent.hpp +1 -1
  167. package/nitrogen/generated/android/c++/JPlaybackProgressUpdatedEvent.hpp +1 -1
  168. package/nitrogen/generated/android/c++/JPlaybackQueueEndedEvent.hpp +1 -1
  169. package/nitrogen/generated/android/c++/JPlaybackState.hpp +10 -11
  170. package/nitrogen/generated/android/c++/JPlayerCapabilities.hpp +1 -1
  171. package/nitrogen/generated/android/c++/JPlayingState.hpp +1 -1
  172. package/nitrogen/generated/android/c++/JProgress.hpp +1 -1
  173. package/nitrogen/generated/android/c++/JRatingType.hpp +8 -9
  174. package/nitrogen/generated/android/c++/JRemoteJumpBackwardEvent.hpp +1 -1
  175. package/nitrogen/generated/android/c++/JRemoteJumpForwardEvent.hpp +1 -1
  176. package/nitrogen/generated/android/c++/JRemotePlayIdEvent.hpp +1 -1
  177. package/nitrogen/generated/android/c++/JRemotePlaySearchEvent.hpp +1 -1
  178. package/nitrogen/generated/android/c++/JRemoteSeekEvent.hpp +1 -1
  179. package/nitrogen/generated/android/c++/JRemoteSetRatingEvent.hpp +1 -1
  180. package/nitrogen/generated/android/c++/JRemoteSkipEvent.hpp +1 -1
  181. package/nitrogen/generated/android/c++/JRepeatMode.hpp +4 -5
  182. package/nitrogen/generated/android/c++/JRepeatModeChangedEvent.hpp +1 -1
  183. package/nitrogen/generated/android/c++/JRequestConfig.hpp +1 -1
  184. package/nitrogen/generated/android/c++/JResolvedTrack.hpp +34 -4
  185. package/nitrogen/generated/android/c++/JRetryConfig.hpp +1 -1
  186. package/nitrogen/generated/android/c++/JSearchMode.hpp +7 -8
  187. package/nitrogen/generated/android/c++/JSearchParams.hpp +1 -1
  188. package/nitrogen/generated/android/c++/JSleepTimer.cpp +1 -1
  189. package/nitrogen/generated/android/c++/JSleepTimer.hpp +4 -4
  190. package/nitrogen/generated/android/c++/JSleepTimerEndOfTrack.hpp +1 -1
  191. package/nitrogen/generated/android/c++/JSleepTimerTime.hpp +1 -1
  192. package/nitrogen/generated/android/c++/JStarRating.hpp +1 -1
  193. package/nitrogen/generated/android/c++/JThumbsRating.hpp +1 -1
  194. package/nitrogen/generated/android/c++/JTimedMetadata.hpp +1 -1
  195. package/nitrogen/generated/android/c++/JTrack.hpp +29 -4
  196. package/nitrogen/generated/android/c++/JTrackLoadEvent.hpp +96 -0
  197. package/nitrogen/generated/android/c++/JTrackMetadata.hpp +1 -1
  198. package/nitrogen/generated/android/c++/JTrackStyle.hpp +3 -4
  199. package/nitrogen/generated/android/c++/JTransformableRequestConfig.hpp +1 -1
  200. package/nitrogen/generated/android/c++/JUpdateOptions.hpp +1 -1
  201. package/nitrogen/generated/android/c++/JVariant_Boolean_AndroidAudioOffloadSettings.cpp +1 -1
  202. package/nitrogen/generated/android/c++/JVariant_Boolean_AndroidAudioOffloadSettings.hpp +3 -3
  203. package/nitrogen/generated/android/c++/JVariant_Boolean_RetryConfig.cpp +1 -1
  204. package/nitrogen/generated/android/c++/JVariant_Boolean_RetryConfig.hpp +3 -3
  205. package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.cpp +1 -1
  206. package/nitrogen/generated/android/c++/JVariant_HeartRating_ThumbsRating_StarRating_PercentageRating.hpp +5 -5
  207. package/nitrogen/generated/android/c++/JVariant_NullType_Double.cpp +1 -1
  208. package/nitrogen/generated/android/c++/JVariant_NullType_Double.hpp +3 -3
  209. package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.cpp +1 -1
  210. package/nitrogen/generated/android/c++/JVariant_NullType_NotificationButtonLayout.hpp +3 -3
  211. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidAudioContentType.kt +3 -1
  212. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidAudioOffloadSettings.kt +2 -2
  213. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidOptions.kt +2 -2
  214. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidPlayerWakeMode.kt +3 -1
  215. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AndroidUpdateOptions.kt +2 -2
  216. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AppKilledPlaybackBehavior.kt +3 -1
  217. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ArtworkRequestConfig.kt +2 -2
  218. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/AudioBrowserOnLoad.kt +1 -1
  219. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryOptimizationStatus.kt +3 -1
  220. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryOptimizationStatusChangedEvent.kt +2 -2
  221. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BatteryWarningPendingChangedEvent.kt +2 -2
  222. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowseError.kt +2 -2
  223. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowseResult.kt +1 -7
  224. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/BrowserSourceCallbackParam.kt +2 -2
  225. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlayNowPlayingButton.kt +3 -1
  226. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/CarPlaySiriListButtonPosition.kt +23 -0
  227. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ChapterMetadata.kt +2 -2
  228. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/EqualizerSettings.kt +2 -2
  229. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FavoriteChangedEvent.kt +2 -2
  230. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormatNavigationErrorParams.kt +2 -2
  231. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/FormattedNavigationError.kt +2 -2
  232. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.kt +1 -1
  233. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.kt +1 -1
  234. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____RequestConfig_std__optional_std__unordered_map_std__string__std__string__.kt +1 -1
  235. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.kt +1 -1
  236. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.kt +1 -1
  237. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.kt +1 -1
  238. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.kt +80 -0
  239. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void.kt +1 -1
  240. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_BatteryOptimizationStatusChangedEvent.kt +1 -1
  241. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_BatteryWarningPendingChangedEvent.kt +1 -1
  242. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_EqualizerSettings.kt +1 -1
  243. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_FavoriteChangedEvent.kt +1 -1
  244. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_IosOutput.kt +1 -1
  245. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_NavigationErrorEvent.kt +1 -1
  246. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_NowPlayingMetadata.kt +1 -1
  247. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_Options.kt +1 -1
  248. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_Playback.kt +1 -1
  249. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackActiveTrackChangedEvent.kt +1 -1
  250. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackErrorEvent.kt +1 -1
  251. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackPlayWhenReadyChangedEvent.kt +1 -1
  252. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackProgressUpdatedEvent.kt +1 -1
  253. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlaybackQueueEndedEvent.kt +1 -1
  254. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_PlayingState.kt +1 -1
  255. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteJumpBackwardEvent.kt +1 -1
  256. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteJumpForwardEvent.kt +1 -1
  257. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemotePlayIdEvent.kt +1 -1
  258. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemotePlaySearchEvent.kt +1 -1
  259. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSeekEvent.kt +1 -1
  260. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSetRatingEvent.kt +1 -1
  261. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RemoteSkipEvent.kt +1 -1
  262. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_RepeatModeChangedEvent.kt +1 -1
  263. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_TimedMetadata.kt +1 -1
  264. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_TrackMetadata.kt +1 -1
  265. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_bool.kt +1 -1
  266. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_double.kt +1 -1
  267. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_FormattedNavigationError_.kt +1 -1
  268. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_ResolvedTrack_.kt +1 -1
  269. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.kt +1 -1
  270. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__string.kt +1 -1
  271. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__vector_ChapterMetadata_.kt +1 -1
  272. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Func_void_std__vector_Track_.kt +1 -1
  273. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HeartRating.kt +2 -2
  274. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HttpMethod.kt +3 -1
  275. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/HybridAudioBrowserSpec.kt +16 -19
  276. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategory.kt +3 -1
  277. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategoryMode.kt +3 -1
  278. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategoryOptions.kt +3 -1
  279. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IOSCategoryPolicy.kt +3 -1
  280. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageContext.kt +2 -2
  281. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageQueryParams.kt +2 -2
  282. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageRowItem.kt +47 -0
  283. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ImageSource.kt +2 -2
  284. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IosOutput.kt +2 -2
  285. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/IosOutputType.kt +3 -1
  286. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaRequestConfig.kt +2 -2
  287. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/MediaTransformParams.kt +2 -2
  288. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeBrowserConfiguration.kt +9 -6
  289. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeRouteEntry.kt +2 -2
  290. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NativeUpdateOptions.kt +2 -2
  291. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationError.kt +2 -2
  292. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorEvent.kt +2 -2
  293. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NavigationErrorType.kt +3 -1
  294. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NitroAndroidUpdateOptions.kt +2 -2
  295. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButton.kt +3 -1
  296. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NotificationButtonLayout.kt +2 -2
  297. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingMetadata.kt +2 -2
  298. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/NowPlayingUpdate.kt +2 -2
  299. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Options.kt +2 -2
  300. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialAndroidSetupPlayerOptions.kt +2 -2
  301. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialIOSSetupPlayerOptions.kt +2 -2
  302. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PartialSetupPlayerOptions.kt +2 -2
  303. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PercentageRating.kt +2 -2
  304. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Playback.kt +2 -2
  305. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackActiveTrackChangedEvent.kt +2 -2
  306. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackError.kt +2 -2
  307. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackErrorEvent.kt +2 -2
  308. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackPlayWhenReadyChangedEvent.kt +2 -2
  309. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackProgressUpdatedEvent.kt +2 -2
  310. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackQueueEndedEvent.kt +2 -2
  311. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlaybackState.kt +3 -1
  312. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayerCapabilities.kt +2 -2
  313. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/PlayingState.kt +2 -2
  314. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Progress.kt +2 -2
  315. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RatingType.kt +3 -1
  316. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteJumpBackwardEvent.kt +2 -2
  317. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteJumpForwardEvent.kt +2 -2
  318. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemotePlayIdEvent.kt +2 -2
  319. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemotePlaySearchEvent.kt +2 -2
  320. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSeekEvent.kt +2 -2
  321. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSetRatingEvent.kt +2 -2
  322. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RemoteSkipEvent.kt +2 -2
  323. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RepeatMode.kt +3 -1
  324. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RepeatModeChangedEvent.kt +2 -2
  325. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RequestConfig.kt +2 -2
  326. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ResolvedTrack.kt +11 -5
  327. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/RetryConfig.kt +2 -2
  328. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchMode.kt +3 -1
  329. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SearchParams.kt +2 -2
  330. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimer.kt +1 -8
  331. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimerEndOfTrack.kt +2 -2
  332. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/SleepTimerTime.kt +2 -2
  333. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/StarRating.kt +2 -2
  334. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/ThumbsRating.kt +2 -2
  335. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TimedMetadata.kt +2 -2
  336. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Track.kt +8 -5
  337. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackLoadEvent.kt +44 -0
  338. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackMetadata.kt +2 -2
  339. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TrackStyle.kt +3 -1
  340. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/TransformableRequestConfig.kt +2 -2
  341. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/UpdateOptions.kt +2 -2
  342. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_AndroidAudioOffloadSettings.kt +1 -7
  343. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_Boolean_RetryConfig.kt +1 -7
  344. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.kt +1 -9
  345. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_NullType_Double.kt +1 -7
  346. package/nitrogen/generated/android/kotlin/com/margelo/nitro/audiobrowser/Variant_NullType_NotificationButtonLayout.kt +1 -7
  347. package/nitrogen/generated/ios/AudioBrowser+autolinking.rb +2 -2
  348. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.cpp +23 -6
  349. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Bridge.hpp +239 -102
  350. package/nitrogen/generated/ios/AudioBrowser-Swift-Cxx-Umbrella.hpp +10 -1
  351. package/nitrogen/generated/ios/AudioBrowserAutolinking.mm +1 -1
  352. package/nitrogen/generated/ios/AudioBrowserAutolinking.swift +9 -8
  353. package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.cpp +1 -1
  354. package/nitrogen/generated/ios/c++/HybridAudioBrowserSpecSwift.hpp +25 -1
  355. package/nitrogen/generated/ios/swift/AndroidAudioContentType.swift +1 -1
  356. package/nitrogen/generated/ios/swift/AndroidAudioOffloadSettings.swift +19 -44
  357. package/nitrogen/generated/ios/swift/AndroidOptions.swift +30 -74
  358. package/nitrogen/generated/ios/swift/AndroidPlayerWakeMode.swift +1 -1
  359. package/nitrogen/generated/ios/swift/AndroidUpdateOptions.swift +44 -112
  360. package/nitrogen/generated/ios/swift/AppKilledPlaybackBehavior.swift +1 -1
  361. package/nitrogen/generated/ios/swift/ArtworkRequestConfig.swift +152 -303
  362. package/nitrogen/generated/ios/swift/BatteryOptimizationStatus.swift +1 -1
  363. package/nitrogen/generated/ios/swift/BatteryOptimizationStatusChangedEvent.swift +3 -10
  364. package/nitrogen/generated/ios/swift/BatteryWarningPendingChangedEvent.swift +3 -10
  365. package/nitrogen/generated/ios/swift/BrowseError.swift +3 -10
  366. package/nitrogen/generated/ios/swift/BrowseResult.swift +1 -1
  367. package/nitrogen/generated/ios/swift/BrowserSourceCallbackParam.swift +20 -45
  368. package/nitrogen/generated/ios/swift/CarPlayNowPlayingButton.swift +1 -1
  369. package/nitrogen/generated/ios/swift/CarPlaySiriListButtonPosition.swift +40 -0
  370. package/nitrogen/generated/ios/swift/ChapterMetadata.swift +23 -60
  371. package/nitrogen/generated/ios/swift/EqualizerSettings.swift +24 -97
  372. package/nitrogen/generated/ios/swift/FavoriteChangedEvent.swift +5 -18
  373. package/nitrogen/generated/ios/swift/FormatNavigationErrorParams.swift +7 -26
  374. package/nitrogen/generated/ios/swift/FormattedNavigationError.swift +5 -18
  375. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__optional_FormattedNavigationError____FormatNavigationErrorParams.swift +1 -2
  376. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____MediaTransformParams.swift +1 -2
  377. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____RequestConfig_std__optional_std__unordered_map_std__string__std__string__.swift +1 -2
  378. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_RequestConfig_____Track.swift +1 -2
  379. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError______BrowserSourceCallbackParam.swift +1 -2
  380. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_std__vector_Track______SearchParams.swift +1 -2
  381. package/nitrogen/generated/ios/swift/Func_std__shared_ptr_Promise_std__shared_ptr_Promise_void_____TrackLoadEvent.swift +61 -0
  382. package/nitrogen/generated/ios/swift/Func_void.swift +1 -2
  383. package/nitrogen/generated/ios/swift/Func_void_BatteryOptimizationStatusChangedEvent.swift +1 -2
  384. package/nitrogen/generated/ios/swift/Func_void_BatteryWarningPendingChangedEvent.swift +1 -2
  385. package/nitrogen/generated/ios/swift/Func_void_EqualizerSettings.swift +1 -2
  386. package/nitrogen/generated/ios/swift/Func_void_FavoriteChangedEvent.swift +1 -2
  387. package/nitrogen/generated/ios/swift/Func_void_IosOutput.swift +1 -2
  388. package/nitrogen/generated/ios/swift/Func_void_NavigationErrorEvent.swift +1 -2
  389. package/nitrogen/generated/ios/swift/Func_void_NowPlayingMetadata.swift +1 -2
  390. package/nitrogen/generated/ios/swift/Func_void_Options.swift +1 -2
  391. package/nitrogen/generated/ios/swift/Func_void_Playback.swift +1 -2
  392. package/nitrogen/generated/ios/swift/Func_void_PlaybackActiveTrackChangedEvent.swift +1 -2
  393. package/nitrogen/generated/ios/swift/Func_void_PlaybackErrorEvent.swift +1 -2
  394. package/nitrogen/generated/ios/swift/Func_void_PlaybackPlayWhenReadyChangedEvent.swift +1 -2
  395. package/nitrogen/generated/ios/swift/Func_void_PlaybackProgressUpdatedEvent.swift +1 -2
  396. package/nitrogen/generated/ios/swift/Func_void_PlaybackQueueEndedEvent.swift +1 -2
  397. package/nitrogen/generated/ios/swift/Func_void_PlayingState.swift +1 -2
  398. package/nitrogen/generated/ios/swift/Func_void_RemoteJumpBackwardEvent.swift +1 -2
  399. package/nitrogen/generated/ios/swift/Func_void_RemoteJumpForwardEvent.swift +1 -2
  400. package/nitrogen/generated/ios/swift/Func_void_RemotePlayIdEvent.swift +1 -2
  401. package/nitrogen/generated/ios/swift/Func_void_RemotePlaySearchEvent.swift +1 -2
  402. package/nitrogen/generated/ios/swift/Func_void_RemoteSeekEvent.swift +1 -2
  403. package/nitrogen/generated/ios/swift/Func_void_RemoteSetRatingEvent.swift +1 -2
  404. package/nitrogen/generated/ios/swift/Func_void_RemoteSkipEvent.swift +1 -2
  405. package/nitrogen/generated/ios/swift/Func_void_RepeatModeChangedEvent.swift +1 -2
  406. package/nitrogen/generated/ios/swift/Func_void_RequestConfig.swift +1 -2
  407. package/nitrogen/generated/ios/swift/Func_void_TimedMetadata.swift +1 -2
  408. package/nitrogen/generated/ios/swift/Func_void_TrackMetadata.swift +1 -2
  409. package/nitrogen/generated/ios/swift/Func_void_bool.swift +1 -2
  410. package/nitrogen/generated/ios/swift/Func_void_double.swift +1 -2
  411. package/nitrogen/generated/ios/swift/Func_void_std__exception_ptr.swift +1 -2
  412. package/nitrogen/generated/ios/swift/Func_void_std__optional_FormattedNavigationError_.swift +1 -2
  413. package/nitrogen/generated/ios/swift/Func_void_std__optional_ResolvedTrack_.swift +1 -2
  414. package/nitrogen/generated/ios/swift/Func_void_std__optional_std__variant_nitro__NullType__SleepTimerTime__SleepTimerEndOfTrack__.swift +1 -2
  415. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_RequestConfig__.swift +1 -2
  416. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_std__variant_ResolvedTrack__BrowseError___.swift +1 -2
  417. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_std__vector_Track___.swift +1 -2
  418. package/nitrogen/generated/ios/swift/Func_void_std__shared_ptr_Promise_void__.swift +64 -0
  419. package/nitrogen/generated/ios/swift/Func_void_std__string.swift +1 -2
  420. package/nitrogen/generated/ios/swift/Func_void_std__variant_ResolvedTrack__BrowseError_.swift +1 -2
  421. package/nitrogen/generated/ios/swift/Func_void_std__vector_ChapterMetadata_.swift +1 -2
  422. package/nitrogen/generated/ios/swift/Func_void_std__vector_Track_.swift +1 -2
  423. package/nitrogen/generated/ios/swift/HeartRating.swift +3 -10
  424. package/nitrogen/generated/ios/swift/HttpMethod.swift +1 -1
  425. package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec.swift +3 -4
  426. package/nitrogen/generated/ios/swift/HybridAudioBrowserSpec_cxx.swift +56 -7
  427. package/nitrogen/generated/ios/swift/IOSCategory.swift +1 -1
  428. package/nitrogen/generated/ios/swift/IOSCategoryMode.swift +1 -1
  429. package/nitrogen/generated/ios/swift/IOSCategoryOptions.swift +1 -1
  430. package/nitrogen/generated/ios/swift/IOSCategoryPolicy.swift +1 -1
  431. package/nitrogen/generated/ios/swift/ImageContext.swift +19 -30
  432. package/nitrogen/generated/ios/swift/ImageQueryParams.swift +19 -44
  433. package/nitrogen/generated/ios/swift/ImageRowItem.swift +76 -0
  434. package/nitrogen/generated/ios/swift/ImageSource.swift +31 -80
  435. package/nitrogen/generated/ios/swift/IosOutput.swift +7 -26
  436. package/nitrogen/generated/ios/swift/IosOutputType.swift +1 -1
  437. package/nitrogen/generated/ios/swift/MediaRequestConfig.swift +162 -301
  438. package/nitrogen/generated/ios/swift/MediaTransformParams.swift +5 -24
  439. package/nitrogen/generated/ios/swift/NativeBrowserConfiguration.swift +143 -232
  440. package/nitrogen/generated/ios/swift/NativeRouteEntry.swift +81 -178
  441. package/nitrogen/generated/ios/swift/NativeUpdateOptions.swift +53 -125
  442. package/nitrogen/generated/ios/swift/NavigationError.swift +23 -53
  443. package/nitrogen/generated/ios/swift/NavigationErrorEvent.swift +3 -16
  444. package/nitrogen/generated/ios/swift/NavigationErrorType.swift +1 -1
  445. package/nitrogen/generated/ios/swift/NitroAndroidUpdateOptions.swift +44 -112
  446. package/nitrogen/generated/ios/swift/NotificationButton.swift +1 -1
  447. package/nitrogen/generated/ios/swift/NotificationButtonLayout.swift +18 -85
  448. package/nitrogen/generated/ios/swift/NowPlayingMetadata.swift +109 -227
  449. package/nitrogen/generated/ios/swift/NowPlayingUpdate.swift +19 -44
  450. package/nitrogen/generated/ios/swift/Options.swift +32 -88
  451. package/nitrogen/generated/ios/swift/PartialAndroidSetupPlayerOptions.swift +101 -201
  452. package/nitrogen/generated/ios/swift/PartialIOSSetupPlayerOptions.swift +25 -85
  453. package/nitrogen/generated/ios/swift/PartialSetupPlayerOptions.swift +35 -91
  454. package/nitrogen/generated/ios/swift/PercentageRating.swift +3 -10
  455. package/nitrogen/generated/ios/swift/Playback.swift +5 -24
  456. package/nitrogen/generated/ios/swift/PlaybackActiveTrackChangedEvent.swift +25 -66
  457. package/nitrogen/generated/ios/swift/PlaybackError.swift +5 -18
  458. package/nitrogen/generated/ios/swift/PlaybackErrorEvent.swift +3 -16
  459. package/nitrogen/generated/ios/swift/PlaybackPlayWhenReadyChangedEvent.swift +3 -10
  460. package/nitrogen/generated/ios/swift/PlaybackProgressUpdatedEvent.swift +9 -34
  461. package/nitrogen/generated/ios/swift/PlaybackQueueEndedEvent.swift +5 -18
  462. package/nitrogen/generated/ios/swift/PlaybackState.swift +1 -1
  463. package/nitrogen/generated/ios/swift/PlayerCapabilities.swift +109 -254
  464. package/nitrogen/generated/ios/swift/PlayingState.swift +5 -18
  465. package/nitrogen/generated/ios/swift/Progress.swift +7 -26
  466. package/nitrogen/generated/ios/swift/RatingType.swift +1 -1
  467. package/nitrogen/generated/ios/swift/RemoteJumpBackwardEvent.swift +3 -10
  468. package/nitrogen/generated/ios/swift/RemoteJumpForwardEvent.swift +3 -10
  469. package/nitrogen/generated/ios/swift/RemotePlayIdEvent.swift +12 -24
  470. package/nitrogen/generated/ios/swift/RemotePlaySearchEvent.swift +3 -10
  471. package/nitrogen/generated/ios/swift/RemoteSeekEvent.swift +3 -10
  472. package/nitrogen/generated/ios/swift/RemoteSetRatingEvent.swift +21 -39
  473. package/nitrogen/generated/ios/swift/RemoteSkipEvent.swift +3 -10
  474. package/nitrogen/generated/ios/swift/RepeatMode.swift +1 -1
  475. package/nitrogen/generated/ios/swift/RepeatModeChangedEvent.swift +3 -10
  476. package/nitrogen/generated/ios/swift/RequestConfig.swift +82 -191
  477. package/nitrogen/generated/ios/swift/ResolvedTrack.swift +164 -333
  478. package/nitrogen/generated/ios/swift/RetryConfig.swift +12 -24
  479. package/nitrogen/generated/ios/swift/SearchMode.swift +1 -1
  480. package/nitrogen/generated/ios/swift/SearchParams.swift +50 -129
  481. package/nitrogen/generated/ios/swift/SleepTimer.swift +1 -1
  482. package/nitrogen/generated/ios/swift/SleepTimerEndOfTrack.swift +3 -10
  483. package/nitrogen/generated/ios/swift/SleepTimerTime.swift +3 -10
  484. package/nitrogen/generated/ios/swift/StarRating.swift +3 -10
  485. package/nitrogen/generated/ios/swift/ThumbsRating.swift +3 -10
  486. package/nitrogen/generated/ios/swift/TimedMetadata.swift +46 -107
  487. package/nitrogen/generated/ios/swift/Track.swift +151 -319
  488. package/nitrogen/generated/ios/swift/TrackLoadEvent.swift +45 -0
  489. package/nitrogen/generated/ios/swift/TrackMetadata.swift +145 -338
  490. package/nitrogen/generated/ios/swift/TrackStyle.swift +1 -1
  491. package/nitrogen/generated/ios/swift/TransformableRequestConfig.swift +128 -252
  492. package/nitrogen/generated/ios/swift/UpdateOptions.swift +53 -125
  493. package/nitrogen/generated/ios/swift/Variant_Bool_AndroidAudioOffloadSettings.swift +1 -1
  494. package/nitrogen/generated/ios/swift/Variant_Bool_RetryConfig.swift +1 -1
  495. package/nitrogen/generated/ios/swift/Variant_HeartRating_ThumbsRating_StarRating_PercentageRating.swift +1 -1
  496. package/nitrogen/generated/ios/swift/Variant_NullType_Double.swift +1 -1
  497. package/nitrogen/generated/ios/swift/Variant_NullType_NotificationButtonLayout.swift +1 -1
  498. package/nitrogen/generated/shared/c++/AndroidAudioContentType.hpp +1 -1
  499. package/nitrogen/generated/shared/c++/AndroidAudioOffloadSettings.hpp +16 -8
  500. package/nitrogen/generated/shared/c++/AndroidOptions.hpp +25 -17
  501. package/nitrogen/generated/shared/c++/AndroidPlayerWakeMode.hpp +1 -1
  502. package/nitrogen/generated/shared/c++/AndroidUpdateOptions.hpp +25 -17
  503. package/nitrogen/generated/shared/c++/AppKilledPlaybackBehavior.hpp +1 -1
  504. package/nitrogen/generated/shared/c++/ArtworkRequestConfig.hpp +43 -35
  505. package/nitrogen/generated/shared/c++/BatteryOptimizationStatus.hpp +1 -1
  506. package/nitrogen/generated/shared/c++/BatteryOptimizationStatusChangedEvent.hpp +13 -5
  507. package/nitrogen/generated/shared/c++/BatteryWarningPendingChangedEvent.hpp +13 -5
  508. package/nitrogen/generated/shared/c++/BrowseError.hpp +13 -5
  509. package/nitrogen/generated/shared/c++/BrowserSourceCallbackParam.hpp +16 -8
  510. package/nitrogen/generated/shared/c++/CarPlayNowPlayingButton.hpp +1 -1
  511. package/nitrogen/generated/shared/c++/CarPlaySiriListButtonPosition.hpp +76 -0
  512. package/nitrogen/generated/shared/c++/ChapterMetadata.hpp +22 -14
  513. package/nitrogen/generated/shared/c++/EqualizerSettings.hpp +34 -26
  514. package/nitrogen/generated/shared/c++/FavoriteChangedEvent.hpp +16 -8
  515. package/nitrogen/generated/shared/c++/FormatNavigationErrorParams.hpp +19 -11
  516. package/nitrogen/generated/shared/c++/FormattedNavigationError.hpp +16 -8
  517. package/nitrogen/generated/shared/c++/HeartRating.hpp +13 -5
  518. package/nitrogen/generated/shared/c++/HttpMethod.hpp +1 -1
  519. package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.cpp +1 -1
  520. package/nitrogen/generated/shared/c++/HybridAudioBrowserSpec.hpp +1 -1
  521. package/nitrogen/generated/shared/c++/IOSCategory.hpp +1 -1
  522. package/nitrogen/generated/shared/c++/IOSCategoryMode.hpp +1 -1
  523. package/nitrogen/generated/shared/c++/IOSCategoryOptions.hpp +1 -1
  524. package/nitrogen/generated/shared/c++/IOSCategoryPolicy.hpp +1 -1
  525. package/nitrogen/generated/shared/c++/ImageContext.hpp +16 -8
  526. package/nitrogen/generated/shared/c++/ImageQueryParams.hpp +16 -8
  527. package/nitrogen/generated/shared/c++/ImageRowItem.hpp +98 -0
  528. package/nitrogen/generated/shared/c++/ImageSource.hpp +22 -14
  529. package/nitrogen/generated/shared/c++/IosOutput.hpp +19 -11
  530. package/nitrogen/generated/shared/c++/IosOutputType.hpp +1 -1
  531. package/nitrogen/generated/shared/c++/MediaRequestConfig.hpp +40 -32
  532. package/nitrogen/generated/shared/c++/MediaTransformParams.hpp +16 -8
  533. package/nitrogen/generated/shared/c++/NativeBrowserConfiguration.hpp +50 -35
  534. package/nitrogen/generated/shared/c++/NativeRouteEntry.hpp +34 -26
  535. package/nitrogen/generated/shared/c++/NativeUpdateOptions.hpp +28 -20
  536. package/nitrogen/generated/shared/c++/NavigationError.hpp +22 -14
  537. package/nitrogen/generated/shared/c++/NavigationErrorEvent.hpp +13 -5
  538. package/nitrogen/generated/shared/c++/NavigationErrorType.hpp +1 -1
  539. package/nitrogen/generated/shared/c++/NitroAndroidUpdateOptions.hpp +25 -17
  540. package/nitrogen/generated/shared/c++/NotificationButton.hpp +1 -1
  541. package/nitrogen/generated/shared/c++/NotificationButtonLayout.hpp +25 -17
  542. package/nitrogen/generated/shared/c++/NowPlayingMetadata.hpp +40 -32
  543. package/nitrogen/generated/shared/c++/NowPlayingUpdate.hpp +16 -8
  544. package/nitrogen/generated/shared/c++/Options.hpp +28 -20
  545. package/nitrogen/generated/shared/c++/PartialAndroidSetupPlayerOptions.hpp +40 -32
  546. package/nitrogen/generated/shared/c++/PartialIOSSetupPlayerOptions.hpp +25 -17
  547. package/nitrogen/generated/shared/c++/PartialSetupPlayerOptions.hpp +22 -14
  548. package/nitrogen/generated/shared/c++/PercentageRating.hpp +13 -5
  549. package/nitrogen/generated/shared/c++/Playback.hpp +16 -8
  550. package/nitrogen/generated/shared/c++/PlaybackActiveTrackChangedEvent.hpp +25 -17
  551. package/nitrogen/generated/shared/c++/PlaybackError.hpp +16 -8
  552. package/nitrogen/generated/shared/c++/PlaybackErrorEvent.hpp +13 -5
  553. package/nitrogen/generated/shared/c++/PlaybackPlayWhenReadyChangedEvent.hpp +13 -5
  554. package/nitrogen/generated/shared/c++/PlaybackProgressUpdatedEvent.hpp +22 -14
  555. package/nitrogen/generated/shared/c++/PlaybackQueueEndedEvent.hpp +16 -8
  556. package/nitrogen/generated/shared/c++/PlaybackState.hpp +1 -1
  557. package/nitrogen/generated/shared/c++/PlayerCapabilities.hpp +46 -38
  558. package/nitrogen/generated/shared/c++/PlayingState.hpp +16 -8
  559. package/nitrogen/generated/shared/c++/Progress.hpp +19 -11
  560. package/nitrogen/generated/shared/c++/RatingType.hpp +1 -1
  561. package/nitrogen/generated/shared/c++/RemoteJumpBackwardEvent.hpp +13 -5
  562. package/nitrogen/generated/shared/c++/RemoteJumpForwardEvent.hpp +13 -5
  563. package/nitrogen/generated/shared/c++/RemotePlayIdEvent.hpp +16 -8
  564. package/nitrogen/generated/shared/c++/RemotePlaySearchEvent.hpp +13 -5
  565. package/nitrogen/generated/shared/c++/RemoteSeekEvent.hpp +13 -5
  566. package/nitrogen/generated/shared/c++/RemoteSetRatingEvent.hpp +13 -5
  567. package/nitrogen/generated/shared/c++/RemoteSkipEvent.hpp +13 -5
  568. package/nitrogen/generated/shared/c++/RepeatMode.hpp +1 -1
  569. package/nitrogen/generated/shared/c++/RepeatModeChangedEvent.hpp +13 -5
  570. package/nitrogen/generated/shared/c++/RequestConfig.hpp +34 -26
  571. package/nitrogen/generated/shared/c++/ResolvedTrack.hpp +79 -57
  572. package/nitrogen/generated/shared/c++/RetryConfig.hpp +16 -8
  573. package/nitrogen/generated/shared/c++/SearchMode.hpp +1 -1
  574. package/nitrogen/generated/shared/c++/SearchParams.hpp +31 -23
  575. package/nitrogen/generated/shared/c++/SleepTimerEndOfTrack.hpp +13 -5
  576. package/nitrogen/generated/shared/c++/SleepTimerTime.hpp +13 -5
  577. package/nitrogen/generated/shared/c++/StarRating.hpp +13 -5
  578. package/nitrogen/generated/shared/c++/ThumbsRating.hpp +13 -5
  579. package/nitrogen/generated/shared/c++/TimedMetadata.hpp +25 -17
  580. package/nitrogen/generated/shared/c++/Track.hpp +70 -54
  581. package/nitrogen/generated/shared/c++/TrackLoadEvent.hpp +93 -0
  582. package/nitrogen/generated/shared/c++/TrackMetadata.hpp +58 -50
  583. package/nitrogen/generated/shared/c++/TrackStyle.hpp +1 -1
  584. package/nitrogen/generated/shared/c++/TransformableRequestConfig.hpp +37 -29
  585. package/nitrogen/generated/shared/c++/UpdateOptions.hpp +28 -20
  586. package/package.json +6 -7
  587. package/src/features/browser.ts +1 -0
  588. package/src/types/browser-native.ts +2 -0
  589. package/src/types/browser-nodes.ts +49 -1
  590. package/src/types/browser.ts +36 -0
  591. package/src/web/NativeAudioBrowser.ts +33 -9
  592. package/src/web/SimpleRouter.test.ts +160 -0
  593. package/src/web/SimpleRouter.ts +10 -8
@@ -7,150 +7,159 @@ class SimpleRouterTest {
7
7
 
8
8
  private val router = SimpleRouter()
9
9
 
10
- @Test
11
- fun `exact match works`() {
12
- val routes = mapOf("/artists" to "config1")
13
- val result = router.findBestMatch("/artists", routes)
10
+ // -- exact matches --
14
11
 
12
+ @Test
13
+ fun `matches a simple path`() {
14
+ val result = router.findBestMatch("/artists", mapOf("/artists" to true))
15
15
  assertNotNull(result)
16
16
  assertEquals("/artists", result!!.first)
17
17
  assertTrue(result.second.params.isEmpty())
18
18
  }
19
19
 
20
20
  @Test
21
- fun `parameter extraction works`() {
22
- val routes = mapOf("/artists/{id}" to "config1")
23
- val result = router.findBestMatch("/artists/123", routes)
24
-
21
+ fun `matches multi-segment paths`() {
22
+ val result = router.findBestMatch("/artists/top/rated", mapOf("/artists/top/rated" to true))
25
23
  assertNotNull(result)
26
- assertEquals("/artists/{id}", result!!.first)
27
- assertEquals("123", result.second.params["id"])
24
+ assertEquals("/artists/top/rated", result!!.first)
28
25
  }
29
26
 
30
27
  @Test
31
- fun `multiple parameters work`() {
32
- val routes = mapOf("/artists/{artistId}/albums/{albumId}" to "config1")
33
- val result = router.findBestMatch("/artists/123/albums/456", routes)
34
-
35
- assertNotNull(result)
36
- assertEquals("123", result!!.second.params["artistId"])
37
- assertEquals("456", result.second.params["albumId"])
28
+ fun `returns null when no route matches`() {
29
+ assertNull(router.findBestMatch("/unknown", mapOf("/artists" to true)))
38
30
  }
39
31
 
40
32
  @Test
41
- fun `specificity works - constants win over parameters`() {
42
- val routes = mapOf("/artists/{id}" to "generic", "/artists/popular" to "specific")
43
- val result = router.findBestMatch("/artists/popular", routes)
44
-
45
- assertEquals("/artists/popular", result!!.first)
33
+ fun `returns null when segment count differs`() {
34
+ assertNull(router.findBestMatch("/artists/123", mapOf("/artists" to true)))
46
35
  }
47
36
 
48
37
  @Test
49
- fun `specificity works - more segments win`() {
50
- val routes = mapOf("/artists" to "short", "/artists/premium" to "longer")
51
-
52
- val result1 = router.findBestMatch("/artists", routes)
53
- assertEquals("/artists", result1!!.first)
54
-
55
- val result2 = router.findBestMatch("/artists/premium", routes)
56
- assertEquals("/artists/premium", result2!!.first)
38
+ fun `returns null when routes are empty`() {
39
+ assertNull(router.findBestMatch("/artists", emptyMap<String, Boolean>()))
57
40
  }
58
41
 
59
42
  @Test
60
- fun `no match returns null`() {
61
- val routes = mapOf("/artists" to "config1")
62
- val result = router.findBestMatch("/songs", routes)
63
-
64
- assertNull(result)
43
+ fun `treats trailing slashes the same as without`() {
44
+ val result = router.findBestMatch("/artists/", mapOf("/artists" to true))
45
+ assertNotNull(result)
46
+ assertEquals("/artists", result!!.first)
65
47
  }
66
48
 
67
- @Test
68
- fun `different segment count returns null`() {
69
- val routes = mapOf("/artists/{id}" to "config1")
70
- val result = router.findBestMatch("/artists/123/extra", routes)
49
+ // -- parameter extraction --
71
50
 
72
- assertNull(result)
51
+ @Test
52
+ fun `extracts a single parameter`() {
53
+ val result = router.findBestMatch("/artists/123", mapOf("/artists/{id}" to true))
54
+ assertNotNull(result)
55
+ assertEquals(mapOf("id" to "123"), result!!.second.params)
73
56
  }
74
57
 
75
58
  @Test
76
- fun `single wildcard matching works`() {
77
- val routes = mapOf("/artists/*" to "wildcard")
78
- val result = router.findBestMatch("/artists/anything", routes)
79
-
59
+ fun `extracts multiple parameters`() {
60
+ val result =
61
+ router.findBestMatch(
62
+ "/artists/123/albums/456",
63
+ mapOf("/artists/{artistId}/albums/{albumId}" to true),
64
+ )
80
65
  assertNotNull(result)
81
- assertEquals("/artists/*", result!!.first)
82
- assertTrue(result.second.params.isEmpty()) // Wildcards don't capture
66
+ assertEquals(mapOf("artistId" to "123", "albumId" to "456"), result!!.second.params)
83
67
  }
84
68
 
69
+ // -- single wildcard --
70
+
85
71
  @Test
86
- fun `tail wildcard matching works`() {
87
- val routes = mapOf("/files/**" to "allFiles")
72
+ fun `matches any single segment`() {
73
+ assertNotNull(router.findBestMatch("/artists/anything", mapOf("/artists/*" to true)))
74
+ }
88
75
 
89
- val result1 = router.findBestMatch("/files/docs/readme.md", routes)
90
- assertNotNull(result1)
91
- assertEquals("docs/readme.md", result1!!.second.params["tail"])
76
+ @Test
77
+ fun `does not extract wildcard value into params`() {
78
+ val result = router.findBestMatch("/artists/anything", mapOf("/artists/*" to true))
79
+ assertTrue(result!!.second.params.isEmpty())
80
+ }
92
81
 
93
- val result2 = router.findBestMatch("/files/images/2023/vacation.jpg", routes)
94
- assertNotNull(result2)
95
- assertEquals("images/2023/vacation.jpg", result2!!.second.params["tail"])
82
+ // -- tail wildcard --
96
83
 
97
- // Also matches shorter paths
98
- val result3 = router.findBestMatch("/files", routes)
99
- assertNotNull(result3)
100
- assertFalse(result3!!.second.params.containsKey("tail")) // No tail captured
84
+ @Test
85
+ fun `matches with no remaining segments and has no tail param`() {
86
+ val result = router.findBestMatch("/files", mapOf("/files/**" to true))
87
+ assertNotNull(result)
88
+ assertTrue(result!!.second.params.isEmpty())
101
89
  }
102
90
 
103
91
  @Test
104
- fun `wildcard specificity works correctly`() {
105
- val routes =
106
- mapOf(
107
- "/artists/*" to "wildcard",
108
- "/artists/{id}" to "parameter",
109
- "/artists/popular" to "constant",
110
- )
92
+ fun `matches with remaining segments and captures tail`() {
93
+ val result = router.findBestMatch("/files/a/b/c", mapOf("/files/**" to true))
94
+ assertNotNull(result)
95
+ assertEquals(mapOf("tail" to "a/b/c"), result!!.second.params)
96
+ }
111
97
 
112
- // Constant wins
113
- val result1 = router.findBestMatch("/artists/popular", routes)
114
- assertEquals("/artists/popular", result1!!.first)
98
+ @Test
99
+ fun `matches with a single remaining segment`() {
100
+ val result = router.findBestMatch("/files/readme.txt", mapOf("/files/**" to true))
101
+ assertNotNull(result)
102
+ assertEquals(mapOf("tail" to "readme.txt"), result!!.second.params)
103
+ }
115
104
 
116
- // Parameter wins over wildcard for non-constant values
117
- val result2 = router.findBestMatch("/artists/123", routes)
118
- assertEquals("/artists/{id}", result2!!.first)
119
- assertEquals("123", result2.second.params["id"])
105
+ @Test
106
+ fun `returns null when prefix segments do not match`() {
107
+ assertNull(router.findBestMatch("/other/a/b", mapOf("/files/**" to true)))
120
108
  }
121
109
 
122
110
  @Test
123
- fun `tail wildcard specificity works`() {
124
- val routes =
125
- mapOf("/api/**" to "catchAll", "/api/users" to "specific", "/api/users/{id}" to "userById")
111
+ fun `works with parameters before tail wildcard`() {
112
+ val result =
113
+ router.findBestMatch("/api/v1/users/list", mapOf("/api/{version}/**" to true))
114
+ assertNotNull(result)
115
+ assertEquals(mapOf("version" to "v1", "tail" to "users/list"), result!!.second.params)
116
+ }
126
117
 
127
- // Specific routes win over tail wildcard
128
- val result1 = router.findBestMatch("/api/users", routes)
129
- assertEquals("/api/users", result1!!.first)
118
+ @Test
119
+ fun `matches any path with bare tail wildcard pattern`() {
120
+ val result = router.findBestMatch("/any/path/here", mapOf("/**" to true))
121
+ assertNotNull(result)
122
+ assertEquals(mapOf("tail" to "any/path/here"), result!!.second.params)
123
+ }
130
124
 
131
- val result2 = router.findBestMatch("/api/users/123", routes)
132
- assertEquals("/api/users/{id}", result2!!.first)
125
+ // -- specificity --
133
126
 
134
- // Tail wildcard catches unmatched paths
135
- val result3 = router.findBestMatch("/api/posts/recent", routes)
136
- assertEquals("/api/**", result3!!.first)
137
- assertEquals("posts/recent", result3.second.params["tail"])
127
+ @Test
128
+ fun `prefers constant segments over parameters`() {
129
+ val routes = mapOf("/artists/{id}" to true, "/artists/top" to true)
130
+ val result = router.findBestMatch("/artists/top", routes)
131
+ assertEquals("/artists/top", result!!.first)
138
132
  }
139
133
 
140
134
  @Test
141
- fun `example from plan works`() {
142
- val routes =
143
- mapOf("/artists" to "generic", "/artists/{id}" to "byId", "/artists/premium" to "premium")
135
+ fun `prefers parameters over wildcards`() {
136
+ val routes = mapOf("/artists/*" to true, "/artists/{id}" to true)
137
+ val result = router.findBestMatch("/artists/123", routes)
138
+ assertEquals("/artists/{id}", result!!.first)
139
+ }
144
140
 
145
- // Test each case
146
- val result1 = router.findBestMatch("/artists", routes)
147
- assertEquals("/artists", result1!!.first)
141
+ @Test
142
+ fun `prefers exact match over tail wildcard`() {
143
+ val routes = mapOf("/api/**" to true, "/api/{version}" to true)
144
+ val result = router.findBestMatch("/api/v1", routes)
145
+ assertEquals("/api/{version}", result!!.first)
146
+ }
148
147
 
149
- val result2 = router.findBestMatch("/artists/123", routes)
150
- assertEquals("/artists/{id}", result2!!.first)
151
- assertEquals("123", result2.second.params["id"])
148
+ @Test
149
+ fun `computes correct specificity for tail wildcard patterns`() {
150
+ // Regression test for issue #27: specificity must account for
151
+ // segment types before the ** wildcard.
152
+ val result = router.findBestMatch("/api/v1/users", mapOf("/api/v1/**" to true))
153
+ // constant "api" (1000) + constant "v1" (1000) + tail(1) + 3 segments = 2004
154
+ assertEquals(2004, result!!.second.specificity)
155
+ }
152
156
 
153
- val result3 = router.findBestMatch("/artists/premium", routes)
154
- assertEquals("/artists/premium", result3!!.first) // More specific than {id}
157
+ @Test
158
+ fun `prefers constant prefix over parameter prefix in tail wildcards`() {
159
+ // Second part of issue #27: with correct specificity, the constant
160
+ // prefix should beat the parameter prefix.
161
+ val routes = mapOf("/api/{version}/**" to true, "/api/v1/**" to true)
162
+ val result = router.findBestMatch("/api/v1/users", routes)
163
+ assertEquals("/api/v1/**", result!!.first)
155
164
  }
156
165
  }
@@ -1,5 +1,6 @@
1
1
  import Foundation
2
2
  import NitroModules
3
+ import os.log
3
4
 
4
5
  /// Flattened browser configuration (matches Kotlin BrowserConfig).
5
6
  ///
@@ -33,6 +34,9 @@ struct BrowserConfig {
33
34
  /// Custom buttons for CarPlay Now Playing screen (e.g., .repeat, .favorite)
34
35
  let carPlayNowPlayingButtons: [CarPlayNowPlayingButton]
35
36
 
37
+ /// Custom handler for track load events (overrides default load behavior)
38
+ let handleTrackLoad: ((_ event: TrackLoadEvent) -> Promise<Promise<Void>>)?
39
+
36
40
  /// Callback to customize navigation error display (for i18n)
37
41
  /// Used by CarPlay and available via `useFormattedNavigationError()` for app UI.
38
42
  let formatNavigationError: ((_ params: FormatNavigationErrorParams) -> Promise<FormattedNavigationError?>)?
@@ -43,6 +47,7 @@ struct BrowserConfig {
43
47
  artwork: ArtworkRequestConfig? = nil,
44
48
  routes: [NativeRouteEntry]? = nil,
45
49
  singleTrack: Bool = false,
50
+ handleTrackLoad: ((_ event: TrackLoadEvent) -> Promise<Promise<Void>>)? = nil,
46
51
  androidControllerOfflineError: Bool = true,
47
52
  carPlayUpNextButton: Bool = true,
48
53
  carPlayNowPlayingButtons: [CarPlayNowPlayingButton] = [],
@@ -53,6 +58,7 @@ struct BrowserConfig {
53
58
  self.artwork = artwork
54
59
  self.routes = routes
55
60
  self.singleTrack = singleTrack
61
+ self.handleTrackLoad = handleTrackLoad
56
62
  self.androidControllerOfflineError = androidControllerOfflineError
57
63
  self.carPlayUpNextButton = carPlayUpNextButton
58
64
  self.carPlayNowPlayingButtons = carPlayNowPlayingButtons
@@ -66,17 +72,37 @@ struct BrowserConfig {
66
72
  artwork = config.artwork
67
73
  routes = config.routes
68
74
  singleTrack = config.singleTrack ?? false
75
+ handleTrackLoad = config.handleTrackLoad
69
76
  androidControllerOfflineError = config.androidControllerOfflineError ?? true
70
77
  carPlayUpNextButton = config.carPlayUpNextButton ?? true
71
78
  carPlayNowPlayingButtons = config.carPlayNowPlayingButtons ?? []
72
79
  formatNavigationError = config.formatNavigationError
73
80
  }
74
81
 
75
- /// Returns true if search functionality is configured (either callback or config).
76
- var hasSearch: Bool {
77
- guard let routes else { return false }
78
- let searchEntry = routes.first { $0.path == BrowserManager.searchRoutePath }
79
- return searchEntry?.searchCallback != nil || searchEntry?.searchConfig != nil
82
+ // MARK: - Track Load Handler
83
+
84
+ private static let logger = Logger(subsystem: "com.audiobrowser", category: "BrowserConfig")
85
+
86
+ /// Awaits the handleTrackLoad callback using the double-Promise pattern required by Nitro.
87
+ ///
88
+ /// Nitro wraps value-returning JS callbacks in Promise<T> for thread safety, so a JS callback
89
+ /// returning Promise<void> becomes Promise<Promise<Void>> on the native side. Both layers
90
+ /// must be awaited to properly wait for the JS work to complete.
91
+ ///
92
+ /// - Returns: true if the handler was present and invoked, false if not configured
93
+ func awaitTrackLoadHandler(event: TrackLoadEvent) async -> Bool {
94
+ guard let handler = handleTrackLoad else { return false }
95
+ do {
96
+ // MainActor: Nitro bridge call must be on main thread (C++ noexcept)
97
+ nonisolated(unsafe) let _handler = handler
98
+ nonisolated(unsafe) let _event = event
99
+ let outerPromise = await MainActor.run { _handler(_event) }
100
+ let innerPromise = try await outerPromise.await()
101
+ try await innerPromise.await()
102
+ } catch {
103
+ Self.logger.error("handleTrackLoad failed: \(error.localizedDescription)")
104
+ }
105
+ return true
80
106
  }
81
107
  }
82
108
 
@@ -183,6 +183,7 @@ final class BrowserManager: @unchecked Sendable {
183
183
  favorited: isFavorited,
184
184
  groupTitle: track.groupTitle,
185
185
  live: track.live,
186
+ imageRow: track.imageRow,
186
187
  )
187
188
  }
188
189
 
@@ -193,6 +194,7 @@ final class BrowserManager: @unchecked Sendable {
193
194
  return ResolvedTrack(
194
195
  url: resolvedTrack.url,
195
196
  children: hydratedChildren,
197
+ carPlaySiriListButton: resolvedTrack.carPlaySiriListButton,
196
198
  src: resolvedTrack.src,
197
199
  artwork: resolvedTrack.artwork,
198
200
  artworkSource: resolvedTrack.artworkSource,
@@ -209,6 +211,7 @@ final class BrowserManager: @unchecked Sendable {
209
211
  favorited: resolvedTrack.favorited,
210
212
  groupTitle: resolvedTrack.groupTitle,
211
213
  live: resolvedTrack.live,
214
+ imageRow: resolvedTrack.imageRow,
212
215
  )
213
216
  }
214
217
 
@@ -336,6 +339,7 @@ final class BrowserManager: @unchecked Sendable {
336
339
  return ResolvedTrack(
337
340
  url: resolvedTrack.url,
338
341
  children: transformedChildren,
342
+ carPlaySiriListButton: resolvedTrack.carPlaySiriListButton,
339
343
  src: resolvedTrack.src,
340
344
  artwork: resolvedTrack.artwork,
341
345
  artworkSource: resolvedTrack.artworkSource,
@@ -352,6 +356,7 @@ final class BrowserManager: @unchecked Sendable {
352
356
  favorited: resolvedTrack.favorited,
353
357
  groupTitle: resolvedTrack.groupTitle,
354
358
  live: resolvedTrack.live,
359
+ imageRow: resolvedTrack.imageRow,
355
360
  )
356
361
  }
357
362
 
@@ -393,7 +398,8 @@ final class BrowserManager: @unchecked Sendable {
393
398
  if let callback = entry.browseCallback {
394
399
  let callbackParam = BrowserSourceCallbackParam(path: path, routeParams: params)
395
400
  // Callback returns Promise<Promise<BrowseResult>> - await both layers
396
- let outerPromise = callback(callbackParam)
401
+ // MainActor: Nitro bridge call must be on main thread (C++ noexcept)
402
+ let outerPromise = await MainActor.run { callback(callbackParam) }
397
403
  let innerPromise = try await outerPromise.await()
398
404
  let result = try await innerPromise.await()
399
405
 
@@ -526,6 +532,7 @@ final class BrowserManager: @unchecked Sendable {
526
532
  favorited: track.favorited,
527
533
  groupTitle: track.groupTitle,
528
534
  live: track.live,
535
+ imageRow: track.imageRow,
529
536
  )
530
537
  }
531
538
 
@@ -553,6 +560,63 @@ final class BrowserManager: @unchecked Sendable {
553
560
  favorited: transformedTrack.favorited,
554
561
  groupTitle: transformedTrack.groupTitle,
555
562
  live: transformedTrack.live,
563
+ imageRow: transformedTrack.imageRow,
564
+ )
565
+ }
566
+
567
+ // Also resolve artwork for image row items
568
+ if let imageRowItems = transformedTrack.imageRow {
569
+ let artworkConfig = routeEntry.artwork ?? config.artwork
570
+ var resolvedItems: [ImageRowItem] = []
571
+ for item in imageRowItems {
572
+ // Create a minimal Track to pass to the artwork resolver
573
+ let itemTrack = Track(
574
+ url: item.url,
575
+ src: nil,
576
+ artwork: item.artwork,
577
+ artworkSource: nil,
578
+ artworkCarPlayTinted: nil,
579
+ title: item.title,
580
+ subtitle: nil,
581
+ artist: nil,
582
+ album: nil,
583
+ description: nil,
584
+ genre: nil,
585
+ duration: nil,
586
+ style: nil,
587
+ childrenStyle: nil,
588
+ favorited: nil,
589
+ groupTitle: nil,
590
+ live: nil,
591
+ imageRow: nil,
592
+ )
593
+ let itemImageSource = await resolver(itemTrack, artworkConfig, browseContext)
594
+ resolvedItems.append(ImageRowItem(
595
+ url: item.url,
596
+ artwork: item.artwork,
597
+ artworkSource: itemImageSource,
598
+ title: item.title,
599
+ ))
600
+ }
601
+ transformedTrack = Track(
602
+ url: transformedTrack.url,
603
+ src: transformedTrack.src,
604
+ artwork: transformedTrack.artwork,
605
+ artworkSource: transformedTrack.artworkSource,
606
+ artworkCarPlayTinted: transformedTrack.artworkCarPlayTinted,
607
+ title: transformedTrack.title,
608
+ subtitle: transformedTrack.subtitle,
609
+ artist: transformedTrack.artist,
610
+ album: transformedTrack.album,
611
+ description: transformedTrack.description,
612
+ genre: transformedTrack.genre,
613
+ duration: transformedTrack.duration,
614
+ style: transformedTrack.style,
615
+ childrenStyle: transformedTrack.childrenStyle,
616
+ favorited: transformedTrack.favorited,
617
+ groupTitle: transformedTrack.groupTitle,
618
+ live: transformedTrack.live,
619
+ imageRow: resolvedItems,
556
620
  )
557
621
  }
558
622
  }
@@ -573,6 +637,7 @@ final class BrowserManager: @unchecked Sendable {
573
637
  return ResolvedTrack(
574
638
  url: BrowserPathHelper.createSearchPath(query),
575
639
  children: hydratedResults,
640
+ carPlaySiriListButton: nil,
576
641
  src: nil,
577
642
  artwork: nil,
578
643
  artworkSource: nil,
@@ -589,6 +654,7 @@ final class BrowserManager: @unchecked Sendable {
589
654
  favorited: nil,
590
655
  groupTitle: nil,
591
656
  live: nil,
657
+ imageRow: nil,
592
658
  )
593
659
  }
594
660
 
@@ -614,7 +680,8 @@ final class BrowserManager: @unchecked Sendable {
614
680
 
615
681
  if let callback = searchEntry.searchCallback {
616
682
  // Callback returns Promise<Promise<[Track]>> - await both layers
617
- let outerPromise = callback(searchParams)
683
+ // MainActor: Nitro bridge call must be on main thread (C++ noexcept)
684
+ let outerPromise = await MainActor.run { callback(searchParams) }
618
685
  let innerPromise = try await outerPromise.await()
619
686
  results = try await innerPromise.await()
620
687
  } else if let searchConfig = searchEntry.searchConfig {
@@ -637,6 +704,7 @@ final class BrowserManager: @unchecked Sendable {
637
704
  return ResolvedTrack(
638
705
  url: BrowserPathHelper.createSearchPath(query),
639
706
  children: hydratedResults,
707
+ carPlaySiriListButton: nil,
640
708
  src: nil,
641
709
  artwork: nil,
642
710
  artworkSource: nil,
@@ -653,6 +721,7 @@ final class BrowserManager: @unchecked Sendable {
653
721
  favorited: nil,
654
722
  groupTitle: nil,
655
723
  live: nil,
724
+ imageRow: nil,
656
725
  )
657
726
  }
658
727
 
@@ -743,27 +812,17 @@ final class BrowserManager: @unchecked Sendable {
743
812
  )
744
813
 
745
814
  logger.debug("resolveMediaUrl: calling transform callback...")
746
- // MediaRequestConfig.transform takes (request, routeParams) - pass nil for routeParams
747
- // Call the JS transform outside the task group to avoid sending-parameter
748
- // data-race warnings (transform and baseRequest aren't Sendable).
749
- let outerPromise = transform(baseRequest, nil)
815
+ // Dispatch the Nitro bridge call to MainActor to avoid C++ noexcept crashes.
816
+ // The generated C++ call() wrapper is noexcept, so any exception from JSI
817
+ // causes std::terminate. Calling from the main thread is safer for JS callbacks.
818
+ // Only the initial call is dispatched; awaiting happens on the background thread.
819
+ let outerPromise = await MainActor.run {
820
+ transform(baseRequest, nil)
821
+ }
822
+ logger.debug("resolveMediaUrl: awaiting outer promise...")
750
823
  let innerPromise = try await outerPromise.await()
751
824
  logger.debug("resolveMediaUrl: awaiting inner promise...")
752
- let transformedConfig = try await withThrowingTaskGroup(of: RequestConfig.self) { group in
753
- group.addTask { [innerPromise] in
754
- return try await innerPromise.await()
755
- }
756
- group.addTask {
757
- // Safety-net timeout: if the JS transform Promise doesn't resolve
758
- // within 10s, bail out. This guards against Nitro bridge hangs when
759
- // concurrent callbacks race.
760
- try await Task.sleep(nanoseconds: 10_000_000_000)
761
- throw CancellationError()
762
- }
763
- let result = try await group.next()!
764
- group.cancelAll()
765
- return result
766
- }
825
+ let transformedConfig = try await innerPromise.await()
767
826
  logger.debug("resolveMediaUrl: transform complete")
768
827
 
769
828
  // Extract values immediately to Swift native types to avoid
@@ -834,6 +893,18 @@ final class BrowserManager: @unchecked Sendable {
834
893
  /// - imageContext: Optional size context for CDN URL generation (nil at browse-time)
835
894
  /// - Returns: ImageSource ready for image loading, or nil if no artwork
836
895
  func resolveArtworkUrl(track: Track, perRouteConfig: ArtworkRequestConfig?, imageContext: ImageContext? = nil) async -> ImageSource? {
896
+ if let artwork = track.artwork, SFSymbolRenderer.isSFSymbol(artwork) {
897
+ let canvasSize: CGSize = if let w = imageContext?.width, let h = imageContext?.height {
898
+ CGSize(width: w, height: h)
899
+ } else {
900
+ SFSymbolRenderer.defaultCanvasSize
901
+ }
902
+ if let uri = await SFSymbolRenderer.shared.render(artwork, canvasSize: canvasSize) {
903
+ return ImageSource(uri: uri, method: nil, headers: nil, body: nil)
904
+ }
905
+ return nil
906
+ }
907
+
837
908
  // Determine effective artwork config: per-route overrides global
838
909
  let effectiveArtworkConfig = perRouteConfig ?? config.artwork
839
910
 
@@ -863,7 +934,8 @@ final class BrowserManager: @unchecked Sendable {
863
934
 
864
935
  // If there's a resolve callback, call it for per-track config
865
936
  if let resolve = artworkConfig.resolve {
866
- let outerPromise = resolve(track)
937
+ // MainActor: Nitro bridge call must be on main thread (C++ noexcept)
938
+ let outerPromise = await MainActor.run { resolve(track) }
867
939
  let innerPromise = try await outerPromise.await()
868
940
  let resolvedConfig = try await innerPromise.await()
869
941
 
@@ -919,7 +991,10 @@ final class BrowserManager: @unchecked Sendable {
919
991
  // Transform will be called at load-time when actual display size is known
920
992
  let hasSize = imageContext?.width != nil || imageContext?.height != nil
921
993
  if let transform = artworkConfig.transform, hasSize {
922
- let outerPromise = transform(MediaTransformParams(request: mergedConfig, context: imageContext))
994
+ // MainActor: Nitro bridge call must be on main thread (C++ noexcept)
995
+ let outerPromise = await MainActor.run {
996
+ transform(MediaTransformParams(request: mergedConfig, context: imageContext))
997
+ }
923
998
  let innerPromise = try await outerPromise.await()
924
999
  let transformedConfig = try await innerPromise.await()
925
1000