@wwdrew/expo-apple-music 1.0.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 (452) hide show
  1. package/ATTRIBUTION.md +24 -0
  2. package/LICENSE +190 -0
  3. package/NOTICE +7 -0
  4. package/README.md +81 -0
  5. package/android/build.gradle +26 -0
  6. package/android/libs/mediaplayback-release-1.1.1.aar +0 -0
  7. package/android/libs/musickitauth-release-1.1.2.aar +0 -0
  8. package/android/src/main/AndroidManifest.xml +16 -0
  9. package/android/src/main/java/expo/modules/applemusic/AndroidCatalogService.kt +86 -0
  10. package/android/src/main/java/expo/modules/applemusic/AndroidDeveloperToken.kt +39 -0
  11. package/android/src/main/java/expo/modules/applemusic/AndroidHistoryService.kt +24 -0
  12. package/android/src/main/java/expo/modules/applemusic/AndroidLibraryMutationsService.kt +30 -0
  13. package/android/src/main/java/expo/modules/applemusic/AndroidLibraryService.kt +61 -0
  14. package/android/src/main/java/expo/modules/applemusic/AndroidPlaybackController.kt +484 -0
  15. package/android/src/main/java/expo/modules/applemusic/AndroidPlaybackObserver.kt +173 -0
  16. package/android/src/main/java/expo/modules/applemusic/AndroidQueueService.kt +78 -0
  17. package/android/src/main/java/expo/modules/applemusic/AndroidRatingsService.kt +27 -0
  18. package/android/src/main/java/expo/modules/applemusic/AndroidRecommendationsService.kt +15 -0
  19. package/android/src/main/java/expo/modules/applemusic/AndroidSubscriptionService.kt +24 -0
  20. package/android/src/main/java/expo/modules/applemusic/AppleMusicErrorCodes.kt +13 -0
  21. package/android/src/main/java/expo/modules/applemusic/AppleMusicErrors.kt +46 -0
  22. package/android/src/main/java/expo/modules/applemusic/AppleMusicHttpMethod.kt +8 -0
  23. package/android/src/main/java/expo/modules/applemusic/AppleMusicJsonMapper.kt +258 -0
  24. package/android/src/main/java/expo/modules/applemusic/AppleMusicNativeLoader.kt +32 -0
  25. package/android/src/main/java/expo/modules/applemusic/AppleMusicRestJson.kt +40 -0
  26. package/android/src/main/java/expo/modules/applemusic/AppleMusicRestQuery.kt +12 -0
  27. package/android/src/main/java/expo/modules/applemusic/AppleMusicRestStack.kt +19 -0
  28. package/android/src/main/java/expo/modules/applemusic/AppleMusicRestTransport.kt +118 -0
  29. package/android/src/main/java/expo/modules/applemusic/AuthenticatedSession.kt +57 -0
  30. package/android/src/main/java/expo/modules/applemusic/BridgeResponses.kt +55 -0
  31. package/android/src/main/java/expo/modules/applemusic/CatalogRestClient.kt +306 -0
  32. package/android/src/main/java/expo/modules/applemusic/ExpoAppleMusicModule.kt +152 -0
  33. package/android/src/main/java/expo/modules/applemusic/HistoryRestClient.kt +60 -0
  34. package/android/src/main/java/expo/modules/applemusic/LibraryIds.kt +6 -0
  35. package/android/src/main/java/expo/modules/applemusic/LibraryMutationsRestClient.kt +95 -0
  36. package/android/src/main/java/expo/modules/applemusic/LibraryRestClient.kt +195 -0
  37. package/android/src/main/java/expo/modules/applemusic/MusicKitAuthContract.kt +78 -0
  38. package/android/src/main/java/expo/modules/applemusic/MusicKitAuthStorage.kt +76 -0
  39. package/android/src/main/java/expo/modules/applemusic/MusicKitTokenProvider.kt +13 -0
  40. package/android/src/main/java/expo/modules/applemusic/PaginationOptions.kt +14 -0
  41. package/android/src/main/java/expo/modules/applemusic/RatingsRestClient.kt +72 -0
  42. package/android/src/main/java/expo/modules/applemusic/RecommendationsRestClient.kt +37 -0
  43. package/android/src/main/java/expo/modules/applemusic/StorefrontRestClient.kt +44 -0
  44. package/android/src/main/java/expo/modules/applemusic/bridge/ExpoBridgeAuth.kt +69 -0
  45. package/android/src/main/java/expo/modules/applemusic/bridge/ExpoBridgeCatalog.kt +76 -0
  46. package/android/src/main/java/expo/modules/applemusic/bridge/ExpoBridgeHistory.kt +35 -0
  47. package/android/src/main/java/expo/modules/applemusic/bridge/ExpoBridgeLibrary.kt +54 -0
  48. package/android/src/main/java/expo/modules/applemusic/bridge/ExpoBridgeLibraryMutations.kt +30 -0
  49. package/android/src/main/java/expo/modules/applemusic/bridge/ExpoBridgePlayer.kt +89 -0
  50. package/android/src/main/java/expo/modules/applemusic/bridge/ExpoBridgeRatings.kt +29 -0
  51. package/android/src/main/java/expo/modules/applemusic/bridge/ExpoBridgeRecommendations.kt +18 -0
  52. package/app.plugin.js +1 -0
  53. package/build/ExpoAppleMusicModule.web.d.ts +15 -0
  54. package/build/ExpoAppleMusicModule.web.d.ts.map +1 -0
  55. package/build/ExpoAppleMusicModule.web.js +33 -0
  56. package/build/ExpoAppleMusicModule.web.js.map +1 -0
  57. package/build/api/call-native.d.ts +6 -0
  58. package/build/api/call-native.d.ts.map +1 -0
  59. package/build/api/call-native.js +35 -0
  60. package/build/api/call-native.js.map +1 -0
  61. package/build/api/decode-jwt-exp.d.ts +5 -0
  62. package/build/api/decode-jwt-exp.d.ts.map +1 -0
  63. package/build/api/decode-jwt-exp.js +28 -0
  64. package/build/api/decode-jwt-exp.js.map +1 -0
  65. package/build/api/library-ids.d.ts +4 -0
  66. package/build/api/library-ids.d.ts.map +1 -0
  67. package/build/api/library-ids.js +11 -0
  68. package/build/api/library-ids.js.map +1 -0
  69. package/build/api/pagination.d.ts +12 -0
  70. package/build/api/pagination.d.ts.map +1 -0
  71. package/build/api/pagination.js +13 -0
  72. package/build/api/pagination.js.map +1 -0
  73. package/build/api/parse-authorize-result.d.ts +3 -0
  74. package/build/api/parse-authorize-result.d.ts.map +1 -0
  75. package/build/api/parse-authorize-result.js +27 -0
  76. package/build/api/parse-authorize-result.js.map +1 -0
  77. package/build/api/require-music-user-token.d.ts +2 -0
  78. package/build/api/require-music-user-token.d.ts.map +1 -0
  79. package/build/api/require-music-user-token.js +14 -0
  80. package/build/api/require-music-user-token.js.map +1 -0
  81. package/build/api/sync-developer-token.d.ts +4 -0
  82. package/build/api/sync-developer-token.d.ts.map +1 -0
  83. package/build/api/sync-developer-token.js +27 -0
  84. package/build/api/sync-developer-token.js.map +1 -0
  85. package/build/bridge/bridge-methods.d.ts +17 -0
  86. package/build/bridge/bridge-methods.d.ts.map +1 -0
  87. package/build/bridge/bridge-methods.js +71 -0
  88. package/build/bridge/bridge-methods.js.map +1 -0
  89. package/build/bridge/bridge-responses.d.ts +64 -0
  90. package/build/bridge/bridge-responses.d.ts.map +1 -0
  91. package/build/bridge/bridge-responses.js +67 -0
  92. package/build/bridge/bridge-responses.js.map +1 -0
  93. package/build/bridge/handlers/auth-bridge.d.ts +11 -0
  94. package/build/bridge/handlers/auth-bridge.d.ts.map +1 -0
  95. package/build/bridge/handlers/auth-bridge.js +49 -0
  96. package/build/bridge/handlers/auth-bridge.js.map +1 -0
  97. package/build/bridge/handlers/catalog-bridge.d.ts +34 -0
  98. package/build/bridge/handlers/catalog-bridge.d.ts.map +1 -0
  99. package/build/bridge/handlers/catalog-bridge.js +58 -0
  100. package/build/bridge/handlers/catalog-bridge.js.map +1 -0
  101. package/build/bridge/handlers/history-bridge.d.ts +19 -0
  102. package/build/bridge/handlers/history-bridge.d.ts.map +1 -0
  103. package/build/bridge/handlers/history-bridge.js +31 -0
  104. package/build/bridge/handlers/history-bridge.js.map +1 -0
  105. package/build/bridge/handlers/index.d.ts +124 -0
  106. package/build/bridge/handlers/index.d.ts.map +1 -0
  107. package/build/bridge/handlers/index.js +21 -0
  108. package/build/bridge/handlers/index.js.map +1 -0
  109. package/build/bridge/handlers/library-bridge.d.ts +23 -0
  110. package/build/bridge/handlers/library-bridge.d.ts.map +1 -0
  111. package/build/bridge/handlers/library-bridge.js +41 -0
  112. package/build/bridge/handlers/library-bridge.js.map +1 -0
  113. package/build/bridge/handlers/library-mutations-bridge.d.ts +16 -0
  114. package/build/bridge/handlers/library-mutations-bridge.d.ts.map +1 -0
  115. package/build/bridge/handlers/library-mutations-bridge.js +20 -0
  116. package/build/bridge/handlers/library-mutations-bridge.js.map +1 -0
  117. package/build/bridge/handlers/player-bridge.d.ts +18 -0
  118. package/build/bridge/handlers/player-bridge.d.ts.map +1 -0
  119. package/build/bridge/handlers/player-bridge.js +42 -0
  120. package/build/bridge/handlers/player-bridge.js.map +1 -0
  121. package/build/bridge/handlers/ratings-bridge.d.ts +15 -0
  122. package/build/bridge/handlers/ratings-bridge.d.ts.map +1 -0
  123. package/build/bridge/handlers/ratings-bridge.js +16 -0
  124. package/build/bridge/handlers/ratings-bridge.js.map +1 -0
  125. package/build/bridge/handlers/recommendations-bridge.d.ts +10 -0
  126. package/build/bridge/handlers/recommendations-bridge.d.ts.map +1 -0
  127. package/build/bridge/handlers/recommendations-bridge.js +14 -0
  128. package/build/bridge/handlers/recommendations-bridge.js.map +1 -0
  129. package/build/constants/apple-music-error-codes.d.ts +22 -0
  130. package/build/constants/apple-music-error-codes.d.ts.map +1 -0
  131. package/build/constants/apple-music-error-codes.js +21 -0
  132. package/build/constants/apple-music-error-codes.js.map +1 -0
  133. package/build/hooks/use-current-song.d.ts +10 -0
  134. package/build/hooks/use-current-song.d.ts.map +1 -0
  135. package/build/hooks/use-current-song.js +35 -0
  136. package/build/hooks/use-current-song.js.map +1 -0
  137. package/build/hooks/use-is-playing.d.ts +6 -0
  138. package/build/hooks/use-is-playing.d.ts.map +1 -0
  139. package/build/hooks/use-is-playing.js +21 -0
  140. package/build/hooks/use-is-playing.js.map +1 -0
  141. package/build/hooks/use-playback-state.d.ts +12 -0
  142. package/build/hooks/use-playback-state.d.ts.map +1 -0
  143. package/build/hooks/use-playback-state.js +41 -0
  144. package/build/hooks/use-playback-state.js.map +1 -0
  145. package/build/index.d.ts +52 -0
  146. package/build/index.d.ts.map +1 -0
  147. package/build/index.js +44 -0
  148. package/build/index.js.map +1 -0
  149. package/build/mappers/apple-music-json-mapper.d.ts +94 -0
  150. package/build/mappers/apple-music-json-mapper.d.ts.map +1 -0
  151. package/build/mappers/apple-music-json-mapper.js +212 -0
  152. package/build/mappers/apple-music-json-mapper.js.map +1 -0
  153. package/build/modules/auth.d.ts +32 -0
  154. package/build/modules/auth.d.ts.map +1 -0
  155. package/build/modules/auth.js +60 -0
  156. package/build/modules/auth.js.map +1 -0
  157. package/build/modules/catalog.d.ts +46 -0
  158. package/build/modules/catalog.d.ts.map +1 -0
  159. package/build/modules/catalog.js +47 -0
  160. package/build/modules/catalog.js.map +1 -0
  161. package/build/modules/history.d.ts +17 -0
  162. package/build/modules/history.d.ts.map +1 -0
  163. package/build/modules/history.js +28 -0
  164. package/build/modules/history.js.map +1 -0
  165. package/build/modules/library-mutations.d.ts +9 -0
  166. package/build/modules/library-mutations.d.ts.map +1 -0
  167. package/build/modules/library-mutations.js +41 -0
  168. package/build/modules/library-mutations.js.map +1 -0
  169. package/build/modules/library.d.ts +21 -0
  170. package/build/modules/library.d.ts.map +1 -0
  171. package/build/modules/library.js +38 -0
  172. package/build/modules/library.js.map +1 -0
  173. package/build/modules/player.d.ts +53 -0
  174. package/build/modules/player.d.ts.map +1 -0
  175. package/build/modules/player.js +68 -0
  176. package/build/modules/player.js.map +1 -0
  177. package/build/modules/ratings.d.ts +10 -0
  178. package/build/modules/ratings.d.ts.map +1 -0
  179. package/build/modules/ratings.js +37 -0
  180. package/build/modules/ratings.js.map +1 -0
  181. package/build/modules/recommendations.d.ts +7 -0
  182. package/build/modules/recommendations.d.ts.map +1 -0
  183. package/build/modules/recommendations.js +15 -0
  184. package/build/modules/recommendations.js.map +1 -0
  185. package/build/native-module.d.ts +5 -0
  186. package/build/native-module.d.ts.map +1 -0
  187. package/build/native-module.js +5 -0
  188. package/build/native-module.js.map +1 -0
  189. package/build/native-module.web.d.ts +11 -0
  190. package/build/native-module.web.d.ts.map +1 -0
  191. package/build/native-module.web.js +11 -0
  192. package/build/native-module.web.js.map +1 -0
  193. package/build/rest/apple-music-rest-stack.d.ts +21 -0
  194. package/build/rest/apple-music-rest-stack.d.ts.map +1 -0
  195. package/build/rest/apple-music-rest-stack.js +21 -0
  196. package/build/rest/apple-music-rest-stack.js.map +1 -0
  197. package/build/rest/apple-music-rest-transport.d.ts +8 -0
  198. package/build/rest/apple-music-rest-transport.d.ts.map +1 -0
  199. package/build/rest/apple-music-rest-transport.js +2 -0
  200. package/build/rest/apple-music-rest-transport.js.map +1 -0
  201. package/build/rest/catalog-rest-client.d.ts +38 -0
  202. package/build/rest/catalog-rest-client.d.ts.map +1 -0
  203. package/build/rest/catalog-rest-client.js +189 -0
  204. package/build/rest/catalog-rest-client.js.map +1 -0
  205. package/build/rest/history-rest-client.d.ts +37 -0
  206. package/build/rest/history-rest-client.d.ts.map +1 -0
  207. package/build/rest/history-rest-client.js +30 -0
  208. package/build/rest/history-rest-client.js.map +1 -0
  209. package/build/rest/library-ids.d.ts +2 -0
  210. package/build/rest/library-ids.d.ts.map +1 -0
  211. package/build/rest/library-ids.js +2 -0
  212. package/build/rest/library-ids.js.map +1 -0
  213. package/build/rest/library-mutations-rest-client.d.ts +22 -0
  214. package/build/rest/library-mutations-rest-client.d.ts.map +1 -0
  215. package/build/rest/library-mutations-rest-client.js +37 -0
  216. package/build/rest/library-mutations-rest-client.js.map +1 -0
  217. package/build/rest/library-rest-client.d.ts +59 -0
  218. package/build/rest/library-rest-client.d.ts.map +1 -0
  219. package/build/rest/library-rest-client.js +141 -0
  220. package/build/rest/library-rest-client.js.map +1 -0
  221. package/build/rest/ratings-rest-client.d.ts +18 -0
  222. package/build/rest/ratings-rest-client.d.ts.map +1 -0
  223. package/build/rest/ratings-rest-client.js +37 -0
  224. package/build/rest/ratings-rest-client.js.map +1 -0
  225. package/build/rest/recommendations-rest-client.d.ts +32 -0
  226. package/build/rest/recommendations-rest-client.d.ts.map +1 -0
  227. package/build/rest/recommendations-rest-client.js +26 -0
  228. package/build/rest/recommendations-rest-client.js.map +1 -0
  229. package/build/rest/resource-ids-query.d.ts +2 -0
  230. package/build/rest/resource-ids-query.d.ts.map +1 -0
  231. package/build/rest/resource-ids-query.js +10 -0
  232. package/build/rest/resource-ids-query.js.map +1 -0
  233. package/build/rest/rest-json.d.ts +11 -0
  234. package/build/rest/rest-json.d.ts.map +1 -0
  235. package/build/rest/rest-json.js +29 -0
  236. package/build/rest/rest-json.js.map +1 -0
  237. package/build/rest/storefront-rest-client.d.ts +14 -0
  238. package/build/rest/storefront-rest-client.d.ts.map +1 -0
  239. package/build/rest/storefront-rest-client.js +36 -0
  240. package/build/rest/storefront-rest-client.js.map +1 -0
  241. package/build/types/album.d.ts +8 -0
  242. package/build/types/album.d.ts.map +1 -0
  243. package/build/types/album.js +2 -0
  244. package/build/types/album.js.map +1 -0
  245. package/build/types/albums-response.d.ts +5 -0
  246. package/build/types/albums-response.d.ts.map +1 -0
  247. package/build/types/albums-response.js +2 -0
  248. package/build/types/albums-response.js.map +1 -0
  249. package/build/types/android-authorize-options.d.ts +18 -0
  250. package/build/types/android-authorize-options.d.ts.map +1 -0
  251. package/build/types/android-authorize-options.js +2 -0
  252. package/build/types/android-authorize-options.js.map +1 -0
  253. package/build/types/artist.d.ts +9 -0
  254. package/build/types/artist.d.ts.map +1 -0
  255. package/build/types/artist.js +2 -0
  256. package/build/types/artist.js.map +1 -0
  257. package/build/types/auth-status.d.ts +19 -0
  258. package/build/types/auth-status.d.ts.map +1 -0
  259. package/build/types/auth-status.js +18 -0
  260. package/build/types/auth-status.js.map +1 -0
  261. package/build/types/authorize-result.d.ts +8 -0
  262. package/build/types/authorize-result.d.ts.map +1 -0
  263. package/build/types/authorize-result.js +2 -0
  264. package/build/types/authorize-result.js.map +1 -0
  265. package/build/types/catalog-album-tracks.d.ts +5 -0
  266. package/build/types/catalog-album-tracks.d.ts.map +1 -0
  267. package/build/types/catalog-album-tracks.js +2 -0
  268. package/build/types/catalog-album-tracks.js.map +1 -0
  269. package/build/types/catalog-charts.d.ts +25 -0
  270. package/build/types/catalog-charts.d.ts.map +1 -0
  271. package/build/types/catalog-charts.js +7 -0
  272. package/build/types/catalog-charts.js.map +1 -0
  273. package/build/types/catalog-resource-type.d.ts +11 -0
  274. package/build/types/catalog-resource-type.d.ts.map +1 -0
  275. package/build/types/catalog-resource-type.js +10 -0
  276. package/build/types/catalog-resource-type.js.map +1 -0
  277. package/build/types/catalog-search.d.ts +24 -0
  278. package/build/types/catalog-search.d.ts.map +1 -0
  279. package/build/types/catalog-search.js +9 -0
  280. package/build/types/catalog-search.js.map +1 -0
  281. package/build/types/check-subscription.d.ts +31 -0
  282. package/build/types/check-subscription.d.ts.map +1 -0
  283. package/build/types/check-subscription.js +5 -0
  284. package/build/types/check-subscription.js.map +1 -0
  285. package/build/types/library-music-videos.d.ts +5 -0
  286. package/build/types/library-music-videos.d.ts.map +1 -0
  287. package/build/types/library-music-videos.js +2 -0
  288. package/build/types/library-music-videos.js.map +1 -0
  289. package/build/types/library-mutations.d.ts +21 -0
  290. package/build/types/library-mutations.d.ts.map +1 -0
  291. package/build/types/library-mutations.js +8 -0
  292. package/build/types/library-mutations.js.map +1 -0
  293. package/build/types/library-search.d.ts +22 -0
  294. package/build/types/library-search.d.ts.map +1 -0
  295. package/build/types/library-search.js +9 -0
  296. package/build/types/library-search.js.map +1 -0
  297. package/build/types/music-item.d.ts +8 -0
  298. package/build/types/music-item.d.ts.map +1 -0
  299. package/build/types/music-item.js +7 -0
  300. package/build/types/music-item.js.map +1 -0
  301. package/build/types/music-video.d.ts +8 -0
  302. package/build/types/music-video.d.ts.map +1 -0
  303. package/build/types/music-video.js +2 -0
  304. package/build/types/music-video.js.map +1 -0
  305. package/build/types/pagination.d.ts +11 -0
  306. package/build/types/pagination.d.ts.map +1 -0
  307. package/build/types/pagination.js +2 -0
  308. package/build/types/pagination.js.map +1 -0
  309. package/build/types/playback-state.d.ts +9 -0
  310. package/build/types/playback-state.d.ts.map +1 -0
  311. package/build/types/playback-state.js +2 -0
  312. package/build/types/playback-state.js.map +1 -0
  313. package/build/types/playback-status.d.ts +10 -0
  314. package/build/types/playback-status.d.ts.map +1 -0
  315. package/build/types/playback-status.js +9 -0
  316. package/build/types/playback-status.js.map +1 -0
  317. package/build/types/playlist.d.ts +15 -0
  318. package/build/types/playlist.d.ts.map +1 -0
  319. package/build/types/playlist.js +2 -0
  320. package/build/types/playlist.js.map +1 -0
  321. package/build/types/rating.d.ts +34 -0
  322. package/build/types/rating.d.ts.map +1 -0
  323. package/build/types/rating.js +26 -0
  324. package/build/types/rating.js.map +1 -0
  325. package/build/types/recent-resource.d.ts +11 -0
  326. package/build/types/recent-resource.d.ts.map +1 -0
  327. package/build/types/recent-resource.js +2 -0
  328. package/build/types/recent-resource.js.map +1 -0
  329. package/build/types/recommendation.d.ts +37 -0
  330. package/build/types/recommendation.d.ts.map +1 -0
  331. package/build/types/recommendation.js +2 -0
  332. package/build/types/recommendation.js.map +1 -0
  333. package/build/types/song.d.ts +8 -0
  334. package/build/types/song.d.ts.map +1 -0
  335. package/build/types/song.js +2 -0
  336. package/build/types/song.js.map +1 -0
  337. package/build/types/station.d.ts +9 -0
  338. package/build/types/station.d.ts.map +1 -0
  339. package/build/types/station.js +2 -0
  340. package/build/types/station.js.map +1 -0
  341. package/build/types/storefront.d.ts +4 -0
  342. package/build/types/storefront.d.ts.map +1 -0
  343. package/build/types/storefront.js +2 -0
  344. package/build/types/storefront.js.map +1 -0
  345. package/build/types/tracks-from-library.d.ts +11 -0
  346. package/build/types/tracks-from-library.d.ts.map +1 -0
  347. package/build/types/tracks-from-library.js +2 -0
  348. package/build/types/tracks-from-library.js.map +1 -0
  349. package/build/utils/apple-music-error.d.ts +10 -0
  350. package/build/utils/apple-music-error.d.ts.map +1 -0
  351. package/build/utils/apple-music-error.js +13 -0
  352. package/build/utils/apple-music-error.js.map +1 -0
  353. package/build/utils/get-error-message.d.ts +2 -0
  354. package/build/utils/get-error-message.d.ts.map +1 -0
  355. package/build/utils/get-error-message.js +21 -0
  356. package/build/utils/get-error-message.js.map +1 -0
  357. package/build/utils/is-library-item.d.ts +2 -0
  358. package/build/utils/is-library-item.d.ts.map +1 -0
  359. package/build/utils/is-library-item.js +4 -0
  360. package/build/utils/is-library-item.js.map +1 -0
  361. package/build/utils/normalize-resource-ids.d.ts +4 -0
  362. package/build/utils/normalize-resource-ids.d.ts.map +1 -0
  363. package/build/utils/normalize-resource-ids.js +12 -0
  364. package/build/utils/normalize-resource-ids.js.map +1 -0
  365. package/build/web/MusicKitLoader.d.ts +11 -0
  366. package/build/web/MusicKitLoader.d.ts.map +1 -0
  367. package/build/web/MusicKitLoader.js +135 -0
  368. package/build/web/MusicKitLoader.js.map +1 -0
  369. package/build/web/WebAppleMusicApiClient.d.ts +151 -0
  370. package/build/web/WebAppleMusicApiClient.d.ts.map +1 -0
  371. package/build/web/WebAppleMusicApiClient.js +139 -0
  372. package/build/web/WebAppleMusicApiClient.js.map +1 -0
  373. package/build/web/WebAppleMusicRestTransport.d.ts +9 -0
  374. package/build/web/WebAppleMusicRestTransport.d.ts.map +1 -0
  375. package/build/web/WebAppleMusicRestTransport.js +31 -0
  376. package/build/web/WebAppleMusicRestTransport.js.map +1 -0
  377. package/build/web/WebPlaybackController.d.ts +12 -0
  378. package/build/web/WebPlaybackController.d.ts.map +1 -0
  379. package/build/web/WebPlaybackController.js +90 -0
  380. package/build/web/WebPlaybackController.js.map +1 -0
  381. package/build/web/WebPlaybackObserver.d.ts +22 -0
  382. package/build/web/WebPlaybackObserver.d.ts.map +1 -0
  383. package/build/web/WebPlaybackObserver.js +106 -0
  384. package/build/web/WebPlaybackObserver.js.map +1 -0
  385. package/build/web/WebQueueService.d.ts +10 -0
  386. package/build/web/WebQueueService.d.ts.map +1 -0
  387. package/build/web/WebQueueService.js +53 -0
  388. package/build/web/WebQueueService.js.map +1 -0
  389. package/build/web/WebSubscriptionService.d.ts +7 -0
  390. package/build/web/WebSubscriptionService.d.ts.map +1 -0
  391. package/build/web/WebSubscriptionService.js +24 -0
  392. package/build/web/WebSubscriptionService.js.map +1 -0
  393. package/build/web/apple-music-errors.d.ts +11 -0
  394. package/build/web/apple-music-errors.d.ts.map +1 -0
  395. package/build/web/apple-music-errors.js +31 -0
  396. package/build/web/apple-music-errors.js.map +1 -0
  397. package/build/web/extract-music-user-token.d.ts +4 -0
  398. package/build/web/extract-music-user-token.d.ts.map +1 -0
  399. package/build/web/extract-music-user-token.js +15 -0
  400. package/build/web/extract-music-user-token.js.map +1 -0
  401. package/build/web/map-auth-status.d.ts +17 -0
  402. package/build/web/map-auth-status.d.ts.map +1 -0
  403. package/build/web/map-auth-status.js +85 -0
  404. package/build/web/map-auth-status.js.map +1 -0
  405. package/build/web/music-kit-api.d.ts +18 -0
  406. package/build/web/music-kit-api.d.ts.map +1 -0
  407. package/build/web/music-kit-api.js +120 -0
  408. package/build/web/music-kit-api.js.map +1 -0
  409. package/build/web/musickit-types.d.ts +70 -0
  410. package/build/web/musickit-types.d.ts.map +1 -0
  411. package/build/web/musickit-types.js +3 -0
  412. package/build/web/musickit-types.js.map +1 -0
  413. package/build/web/pagination.d.ts +2 -0
  414. package/build/web/pagination.d.ts.map +1 -0
  415. package/build/web/pagination.js +2 -0
  416. package/build/web/pagination.js.map +1 -0
  417. package/expo-module.config.json +19 -0
  418. package/ios/AppleMusicBridgeError.swift +60 -0
  419. package/ios/AppleMusicErrorCodes.swift +11 -0
  420. package/ios/AppleMusicRestClient.swift +213 -0
  421. package/ios/AuthenticatedSession.swift +64 -0
  422. package/ios/BridgePagination.swift +17 -0
  423. package/ios/BridgeResponses.swift +82 -0
  424. package/ios/CatalogSearchStore.swift +13 -0
  425. package/ios/CatalogSearchStoreFactory.swift +31 -0
  426. package/ios/CatalogService.swift +307 -0
  427. package/ios/ExpoAppleMusic.podspec +29 -0
  428. package/ios/ExpoAppleMusicModule.swift +505 -0
  429. package/ios/HistoryService.swift +53 -0
  430. package/ios/LibraryMutationsService.swift +63 -0
  431. package/ios/LibraryService.swift +313 -0
  432. package/ios/MusicItemMapper.swift +171 -0
  433. package/ios/MusicKitAuthStorage.swift +38 -0
  434. package/ios/MusicKitCatalogSearchStore.swift +62 -0
  435. package/ios/PlaybackController.swift +201 -0
  436. package/ios/PlaybackObserver.swift +225 -0
  437. package/ios/QueueService.swift +166 -0
  438. package/ios/RatingsService.swift +66 -0
  439. package/ios/RecommendationsService.swift +34 -0
  440. package/ios/RestCatalogSearchStore.swift +62 -0
  441. package/ios/RestJsonMapper.swift +268 -0
  442. package/ios/StorefrontService.swift +55 -0
  443. package/ios/SubscriptionService.swift +119 -0
  444. package/ios/bridge/ExpoBridgeCatalog.swift +98 -0
  445. package/ios/bridge/ExpoBridgeHistory.swift +71 -0
  446. package/ios/bridge/ExpoBridgeLibrary.swift +93 -0
  447. package/ios/bridge/ExpoBridgeRecommendations.swift +28 -0
  448. package/package.json +89 -0
  449. package/plugin/build/index.d.ts +5 -0
  450. package/plugin/build/index.js +10 -0
  451. package/plugin/build/with-expo-apple-music.d.ts +10 -0
  452. package/plugin/build/with-expo-apple-music.js +50 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebPlaybackObserver.js","sourceRoot":"","sources":["../../src/web/WebPlaybackObserver.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,qBAAqB,EAAE,MAAM,yBAAyB,CAAC;AAChE,OAAO,EAAE,oBAAoB,EAAE,MAAM,kBAAkB,CAAC;AAExD,MAAM,eAAe,GAAG;IACtB,uBAAuB;IACvB,qBAAqB;IACrB,sBAAsB;IACtB,iBAAiB;CACT,CAAC;AAOX,MAAM,OAAO,mBAAmB;IACtB,UAAU,GAA0C,IAAI,CAAC;IACzD,aAAa,GAA2B,IAAI,CAAC;IAC7C,yBAAyB,GAAG,KAAK,CAAC;IACzB,QAAQ,GAAG,IAAI,qBAAqB,EAAE,CAAC;IACvC,QAAQ,GAAG;QAC1B,aAAa,EAAE,GAAG,EAAE;YAClB,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC;YACnC,IAAI,OAAO,EAAE,CAAC;gBACZ,KAAK,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;YAC/B,CAAC;QACH,CAAC;QACD,SAAS,EAAE,GAAG,EAAE;YACd,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC;YACnC,IAAI,OAAO,EAAE,CAAC;gBACZ,KAAK,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;YACrC,CAAC;QACH,CAAC;KACF,CAAC;IAEF,KAAK,CAAC,OAAwB;QAC5B,IAAI,CAAC,IAAI,EAAE,CAAC;QACZ,IAAI,CAAC,aAAa,GAAG,OAAO,CAAC;QAC7B,KAAK,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAC3C,IAAI,CAAC,UAAU,GAAG,WAAW,CAAC,GAAG,EAAE;YACjC,KAAK,IAAI,CAAC,IAAI,EAAE,CAAC;QACnB,CAAC,EAAE,IAAI,CAAC,CAAC;IACX,CAAC;IAED,IAAI;QACF,IAAI,CAAC,aAAa,GAAG,IAAI,CAAC;QAC1B,IAAI,CAAC,yBAAyB,GAAG,KAAK,CAAC;QACvC,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,aAAa,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC/B,IAAI,CAAC,UAAU,GAAG,IAAI,CAAC;QACzB,CAAC;QACD,KAAK,IAAI,CAAC,uBAAuB,EAAE,CAAC;IACtC,CAAC;IAED,YAAY,CAAC,OAAwB;QACnC,OAAO,eAAe,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,OAAO,CAAC,aAAa,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC;IAC3E,CAAC;IAEO,KAAK,CAAC,IAAI;QAChB,MAAM,OAAO,GAAG,IAAI,CAAC,aAAa,CAAC;QACnC,IAAI,CAAC,OAAO,EAAE,CAAC;YACb,OAAO;QACT,CAAC;QACD,IAAI,CAAC,IAAI,CAAC,yBAAyB,EAAE,CAAC;YACpC,MAAM,IAAI,CAAC,uBAAuB,CAAC,OAAO,CAAC,CAAC;QAC9C,CAAC;QACD,MAAM,IAAI,CAAC,cAAc,CAAC,OAAO,CAAC,CAAC;IACrC,CAAC;IAEO,KAAK,CAAC,uBAAuB,CAAC,OAAwB;QAC5D,IAAI,IAAI,CAAC,yBAAyB,EAAE,CAAC;YACnC,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,oBAAoB,EAAE,CAAC;QAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO;QACT,CAAC;QACD,KAAK,CAAC,gBAAgB,CAAC,wBAAwB,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QAC9E,KAAK,CAAC,gBAAgB,CAAC,oBAAoB,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACtE,IAAI,CAAC,yBAAyB,GAAG,IAAI,CAAC;QACtC,MAAM,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAC9B,MAAM,IAAI,CAAC,eAAe,CAAC,OAAO,CAAC,CAAC;IACtC,CAAC;IAEO,KAAK,CAAC,uBAAuB;QACnC,IAAI,CAAC,IAAI,CAAC,yBAAyB,EAAE,CAAC;YACpC,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,oBAAoB,EAAE,CAAC;QAC3C,IAAI,CAAC,KAAK,EAAE,CAAC;YACX,OAAO;QACT,CAAC;QACD,KAAK,CAAC,mBAAmB,CAAC,wBAAwB,EAAE,IAAI,CAAC,QAAQ,CAAC,aAAa,CAAC,CAAC;QACjF,KAAK,CAAC,mBAAmB,CAAC,oBAAoB,EAAE,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;QACzE,IAAI,CAAC,yBAAyB,GAAG,KAAK,CAAC;IACzC,CAAC;IAEO,KAAK,CAAC,SAAS,CAAC,OAAwB;QAC9C,IAAI,OAAO,CAAC,aAAa,CAAC,uBAAuB,CAAC,KAAK,CAAC,EAAE,CAAC;YACzD,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,uBAAuB,EAAE,KAAK,CAAC,CAAC;IAC/C,CAAC;IAEO,KAAK,CAAC,eAAe,CAAC,OAAwB;QACpD,IAAI,OAAO,CAAC,aAAa,CAAC,qBAAqB,CAAC,KAAK,CAAC,EAAE,CAAC;YACvD,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,qBAAqB,EAAE,EAAE,WAAW,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1E,CAAC;IAEO,KAAK,CAAC,cAAc,CAAC,OAAwB;QACnD,IAAI,OAAO,CAAC,aAAa,CAAC,sBAAsB,CAAC,KAAK,CAAC,EAAE,CAAC;YACxD,OAAO;QACT,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,IAAI,CAAC,QAAQ,CAAC,YAAY,EAAE,CAAC;QACjD,OAAO,CAAC,IAAI,CAAC,sBAAsB,EAAE,EAAE,YAAY,EAAE,KAAK,CAAC,YAAY,IAAI,CAAC,EAAE,CAAC,CAAC;IAClF,CAAC;CACF","sourcesContent":["import { WebPlaybackController } from './WebPlaybackController';\nimport { getMusicIfConfigured } from './MusicKitLoader';\n\nconst PLAYBACK_EVENTS = [\n 'onPlaybackStateChange',\n 'onCurrentSongChange',\n 'onPlaybackTimeUpdate',\n 'onPlaybackError',\n] as const;\n\ninterface PlaybackEmitter {\n emit(eventName: string, payload: unknown): void;\n listenerCount(eventName: string): number;\n}\n\nexport class WebPlaybackObserver {\n private intervalId: ReturnType<typeof setInterval> | null = null;\n private activeEmitter: PlaybackEmitter | null = null;\n private musicKitListenersAttached = false;\n private readonly playback = new WebPlaybackController();\n private readonly handlers = {\n playbackState: () => {\n const emitter = this.activeEmitter;\n if (emitter) {\n void this.emitState(emitter);\n }\n },\n mediaItem: () => {\n const emitter = this.activeEmitter;\n if (emitter) {\n void this.emitCurrentSong(emitter);\n }\n },\n };\n\n start(emitter: PlaybackEmitter): void {\n this.stop();\n this.activeEmitter = emitter;\n void this.attachMusicKitListeners(emitter);\n this.intervalId = setInterval(() => {\n void this.tick();\n }, 1000);\n }\n\n stop(): void {\n this.activeEmitter = null;\n this.musicKitListenersAttached = false;\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n void this.detachMusicKitListeners();\n }\n\n hasListeners(emitter: PlaybackEmitter): boolean {\n return PLAYBACK_EVENTS.some((event) => emitter.listenerCount(event) > 0);\n }\n\n private async tick(): Promise<void> {\n const emitter = this.activeEmitter;\n if (!emitter) {\n return;\n }\n if (!this.musicKitListenersAttached) {\n await this.attachMusicKitListeners(emitter);\n }\n await this.emitTimeUpdate(emitter);\n }\n\n private async attachMusicKitListeners(emitter: PlaybackEmitter): Promise<void> {\n if (this.musicKitListenersAttached) {\n return;\n }\n const music = await getMusicIfConfigured();\n if (!music) {\n return;\n }\n music.addEventListener('playbackStateDidChange', this.handlers.playbackState);\n music.addEventListener('mediaItemDidChange', this.handlers.mediaItem);\n this.musicKitListenersAttached = true;\n await this.emitState(emitter);\n await this.emitCurrentSong(emitter);\n }\n\n private async detachMusicKitListeners(): Promise<void> {\n if (!this.musicKitListenersAttached) {\n return;\n }\n const music = await getMusicIfConfigured();\n if (!music) {\n return;\n }\n music.removeEventListener('playbackStateDidChange', this.handlers.playbackState);\n music.removeEventListener('mediaItemDidChange', this.handlers.mediaItem);\n this.musicKitListenersAttached = false;\n }\n\n private async emitState(emitter: PlaybackEmitter): Promise<void> {\n if (emitter.listenerCount('onPlaybackStateChange') === 0) {\n return;\n }\n const state = await this.playback.currentState();\n emitter.emit('onPlaybackStateChange', state);\n }\n\n private async emitCurrentSong(emitter: PlaybackEmitter): Promise<void> {\n if (emitter.listenerCount('onCurrentSongChange') === 0) {\n return;\n }\n const state = await this.playback.currentState();\n emitter.emit('onCurrentSongChange', { currentSong: state.currentSong });\n }\n\n private async emitTimeUpdate(emitter: PlaybackEmitter): Promise<void> {\n if (emitter.listenerCount('onPlaybackTimeUpdate') === 0) {\n return;\n }\n const state = await this.playback.currentState();\n emitter.emit('onPlaybackTimeUpdate', { playbackTime: state.playbackTime ?? 0 });\n }\n}\n"]}
@@ -0,0 +1,10 @@
1
+ import { WebAppleMusicApiClient } from './WebAppleMusicApiClient';
2
+ export declare class WebQueueService {
3
+ private readonly api;
4
+ constructor(api?: WebAppleMusicApiClient);
5
+ setQueue(itemId: string, type: string): Promise<void>;
6
+ private setCatalogQueue;
7
+ playLibrarySong(musicUserToken: string, songId: string): Promise<void>;
8
+ playLibraryPlaylist(musicUserToken: string, playlistId: string, startingAt: number): Promise<void>;
9
+ }
10
+ //# sourceMappingURL=WebQueueService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebQueueService.d.ts","sourceRoot":"","sources":["../../src/web/WebQueueService.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAiBlE,qBAAa,eAAe;IACd,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,yBAA+B;IAEzD,QAAQ,CAAC,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;YAW7C,eAAe;IASvB,eAAe,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAMtE,mBAAmB,CAAC,cAAc,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAUzG"}
@@ -0,0 +1,53 @@
1
+ import { isLibraryId } from '../rest/library-ids';
2
+ import * as errors from './apple-music-errors';
3
+ import { WebAppleMusicApiClient } from './WebAppleMusicApiClient';
4
+ import { getMusic } from './MusicKitLoader';
5
+ function parseMediaType(type) {
6
+ switch (type) {
7
+ case 'song':
8
+ case 'album':
9
+ case 'playlist':
10
+ case 'station':
11
+ return type;
12
+ default:
13
+ throw errors.unknownMediaType(type);
14
+ }
15
+ }
16
+ export class WebQueueService {
17
+ api;
18
+ constructor(api = new WebAppleMusicApiClient()) {
19
+ this.api = api;
20
+ }
21
+ async setQueue(itemId, type) {
22
+ const mediaType = parseMediaType(type);
23
+ if (isLibraryId(itemId)) {
24
+ throw errors.apiError('Library queue requires a music user token. Use Player.playLibrarySong or playLibraryPlaylist.');
25
+ }
26
+ else {
27
+ await this.setCatalogQueue(itemId, mediaType);
28
+ }
29
+ }
30
+ async setCatalogQueue(itemId, type) {
31
+ const music = await getMusic();
32
+ if (type === 'station') {
33
+ await music.setQueue({ station: itemId });
34
+ return;
35
+ }
36
+ await music.setQueue({ [type]: itemId });
37
+ }
38
+ async playLibrarySong(musicUserToken, songId) {
39
+ const catalogId = await this.api.resolveCatalogPlaybackId(musicUserToken, songId, 'song');
40
+ const music = await getMusic();
41
+ await music.setQueue({ songs: [catalogId] });
42
+ }
43
+ async playLibraryPlaylist(musicUserToken, playlistId, startingAt) {
44
+ const catalogIds = await this.api.resolveLibrarySongCatalogIds(musicUserToken, playlistId);
45
+ if (catalogIds.length === 0) {
46
+ throw errors.noSongsInPlaylist();
47
+ }
48
+ const startIndex = startingAt === -1 ? 0 : startingAt >= 0 && startingAt < catalogIds.length ? startingAt : 0;
49
+ const music = await getMusic();
50
+ await music.setQueue({ songs: catalogIds, startWith: startIndex });
51
+ }
52
+ }
53
+ //# sourceMappingURL=WebQueueService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebQueueService.js","sourceRoot":"","sources":["../../src/web/WebQueueService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAClD,OAAO,KAAK,MAAM,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAI5C,SAAS,cAAc,CAAC,IAAY;IAClC,QAAQ,IAAI,EAAE,CAAC;QACb,KAAK,MAAM,CAAC;QACZ,KAAK,OAAO,CAAC;QACb,KAAK,UAAU,CAAC;QAChB,KAAK,SAAS;YACZ,OAAO,IAAI,CAAC;QACd;YACE,MAAM,MAAM,CAAC,gBAAgB,CAAC,IAAI,CAAC,CAAC;IACxC,CAAC;AACH,CAAC;AAED,MAAM,OAAO,eAAe;IACG;IAA7B,YAA6B,MAAM,IAAI,sBAAsB,EAAE;QAAlC,QAAG,GAAH,GAAG,CAA+B;IAAG,CAAC;IAEnE,KAAK,CAAC,QAAQ,CAAC,MAAc,EAAE,IAAY;QACzC,MAAM,SAAS,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;QACvC,IAAI,WAAW,CAAC,MAAM,CAAC,EAAE,CAAC;YACxB,MAAM,MAAM,CAAC,QAAQ,CACnB,+FAA+F,CAChG,CAAC;QACJ,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,CAAC,eAAe,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QAChD,CAAC;IACH,CAAC;IAEO,KAAK,CAAC,eAAe,CAAC,MAAc,EAAE,IAAe;QAC3D,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;QAC/B,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;YACvB,MAAM,KAAK,CAAC,QAAQ,CAAC,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;YAC1C,OAAO;QACT,CAAC;QACD,MAAM,KAAK,CAAC,QAAQ,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED,KAAK,CAAC,eAAe,CAAC,cAAsB,EAAE,MAAc;QAC1D,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,wBAAwB,CAAC,cAAc,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;QAC1F,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;QAC/B,MAAM,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,CAAC,SAAS,CAAC,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED,KAAK,CAAC,mBAAmB,CAAC,cAAsB,EAAE,UAAkB,EAAE,UAAkB;QACtF,MAAM,UAAU,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,4BAA4B,CAAC,cAAc,EAAE,UAAU,CAAC,CAAC;QAC3F,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC5B,MAAM,MAAM,CAAC,iBAAiB,EAAE,CAAC;QACnC,CAAC;QACD,MAAM,UAAU,GACd,UAAU,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,UAAU,IAAI,CAAC,IAAI,UAAU,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,CAAC,CAAC;QAC7F,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;QAC/B,MAAM,KAAK,CAAC,QAAQ,CAAC,EAAE,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,CAAC,CAAC;IACrE,CAAC;CACF","sourcesContent":["import { isLibraryId } from '../rest/library-ids';\nimport * as errors from './apple-music-errors';\nimport { WebAppleMusicApiClient } from './WebAppleMusicApiClient';\nimport { getMusic } from './MusicKitLoader';\n\ntype MediaType = 'song' | 'album' | 'playlist' | 'station';\n\nfunction parseMediaType(type: string): MediaType {\n switch (type) {\n case 'song':\n case 'album':\n case 'playlist':\n case 'station':\n return type;\n default:\n throw errors.unknownMediaType(type);\n }\n}\n\nexport class WebQueueService {\n constructor(private readonly api = new WebAppleMusicApiClient()) {}\n\n async setQueue(itemId: string, type: string): Promise<void> {\n const mediaType = parseMediaType(type);\n if (isLibraryId(itemId)) {\n throw errors.apiError(\n 'Library queue requires a music user token. Use Player.playLibrarySong or playLibraryPlaylist.',\n );\n } else {\n await this.setCatalogQueue(itemId, mediaType);\n }\n }\n\n private async setCatalogQueue(itemId: string, type: MediaType): Promise<void> {\n const music = await getMusic();\n if (type === 'station') {\n await music.setQueue({ station: itemId });\n return;\n }\n await music.setQueue({ [type]: itemId });\n }\n\n async playLibrarySong(musicUserToken: string, songId: string): Promise<void> {\n const catalogId = await this.api.resolveCatalogPlaybackId(musicUserToken, songId, 'song');\n const music = await getMusic();\n await music.setQueue({ songs: [catalogId] });\n }\n\n async playLibraryPlaylist(musicUserToken: string, playlistId: string, startingAt: number): Promise<void> {\n const catalogIds = await this.api.resolveLibrarySongCatalogIds(musicUserToken, playlistId);\n if (catalogIds.length === 0) {\n throw errors.noSongsInPlaylist();\n }\n const startIndex =\n startingAt === -1 ? 0 : startingAt >= 0 && startingAt < catalogIds.length ? startingAt : 0;\n const music = await getMusic();\n await music.setQueue({ songs: catalogIds, startWith: startIndex });\n }\n}\n"]}
@@ -0,0 +1,7 @@
1
+ import { WebAppleMusicApiClient } from './WebAppleMusicApiClient';
2
+ export declare class WebSubscriptionService {
3
+ private readonly api;
4
+ constructor(api?: WebAppleMusicApiClient);
5
+ checkSubscription(musicUserToken: string): Promise<Record<string, unknown>>;
6
+ }
7
+ //# sourceMappingURL=WebSubscriptionService.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebSubscriptionService.d.ts","sourceRoot":"","sources":["../../src/web/WebSubscriptionService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAIlE,qBAAa,sBAAsB;IACrB,OAAO,CAAC,QAAQ,CAAC,GAAG;gBAAH,GAAG,yBAA+B;IAEzD,iBAAiB,CAAC,cAAc,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAgBlF"}
@@ -0,0 +1,24 @@
1
+ import { WebAppleMusicApiClient } from './WebAppleMusicApiClient';
2
+ import * as errors from './apple-music-errors';
3
+ import { getMusic } from './MusicKitLoader';
4
+ export class WebSubscriptionService {
5
+ api;
6
+ constructor(api = new WebAppleMusicApiClient()) {
7
+ this.api = api;
8
+ }
9
+ async checkSubscription(musicUserToken) {
10
+ const music = await getMusic();
11
+ if (!music.isAuthorized) {
12
+ throw errors.missingTokens();
13
+ }
14
+ const libraryOk = await this.api.probeLibraryAccess(musicUserToken);
15
+ const canPlay = libraryOk;
16
+ return {
17
+ canPlayCatalogContent: canPlay,
18
+ canBecomeSubscriber: false,
19
+ hasCloudLibraryEnabled: libraryOk,
20
+ isMusicCatalogSubscriptionEligible: false,
21
+ };
22
+ }
23
+ }
24
+ //# sourceMappingURL=WebSubscriptionService.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"WebSubscriptionService.js","sourceRoot":"","sources":["../../src/web/WebSubscriptionService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,0BAA0B,CAAC;AAClE,OAAO,KAAK,MAAM,MAAM,sBAAsB,CAAC;AAC/C,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE5C,MAAM,OAAO,sBAAsB;IACJ;IAA7B,YAA6B,MAAM,IAAI,sBAAsB,EAAE;QAAlC,QAAG,GAAH,GAAG,CAA+B;IAAG,CAAC;IAEnE,KAAK,CAAC,iBAAiB,CAAC,cAAsB;QAC5C,MAAM,KAAK,GAAG,MAAM,QAAQ,EAAE,CAAC;QAC/B,IAAI,CAAC,KAAK,CAAC,YAAY,EAAE,CAAC;YACxB,MAAM,MAAM,CAAC,aAAa,EAAE,CAAC;QAC/B,CAAC;QAED,MAAM,SAAS,GAAG,MAAM,IAAI,CAAC,GAAG,CAAC,kBAAkB,CAAC,cAAc,CAAC,CAAC;QACpE,MAAM,OAAO,GAAG,SAAS,CAAC;QAE1B,OAAO;YACL,qBAAqB,EAAE,OAAO;YAC9B,mBAAmB,EAAE,KAAK;YAC1B,sBAAsB,EAAE,SAAS;YACjC,kCAAkC,EAAE,KAAK;SAC1C,CAAC;IACJ,CAAC;CACF","sourcesContent":["import { WebAppleMusicApiClient } from './WebAppleMusicApiClient';\nimport * as errors from './apple-music-errors';\nimport { getMusic } from './MusicKitLoader';\n\nexport class WebSubscriptionService {\n constructor(private readonly api = new WebAppleMusicApiClient()) {}\n\n async checkSubscription(musicUserToken: string): Promise<Record<string, unknown>> {\n const music = await getMusic();\n if (!music.isAuthorized) {\n throw errors.missingTokens();\n }\n\n const libraryOk = await this.api.probeLibraryAccess(musicUserToken);\n const canPlay = libraryOk;\n\n return {\n canPlayCatalogContent: canPlay,\n canBecomeSubscriber: false,\n hasCloudLibraryEnabled: libraryOk,\n isMusicCatalogSubscriptionEligible: false,\n };\n }\n}\n"]}
@@ -0,0 +1,11 @@
1
+ import { CodedError } from 'expo-modules-core';
2
+ export declare function missingDeveloperToken(): CodedError;
3
+ export declare function missingTokens(): CodedError;
4
+ export declare function permissionDenied(): CodedError;
5
+ export declare function apiError(message: string, code?: "ERROR"): CodedError;
6
+ export declare function playlistNotFound(): CodedError;
7
+ export declare function itemNotFound(item: string, inLibrary: boolean): CodedError;
8
+ export declare function unknownMediaType(type: string): CodedError;
9
+ export declare function unsupportedLibraryType(type: string): CodedError;
10
+ export declare function noSongsInPlaylist(): CodedError;
11
+ //# sourceMappingURL=apple-music-errors.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apple-music-errors.d.ts","sourceRoot":"","sources":["../../src/web/apple-music-errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAG/C,wBAAgB,qBAAqB,IAAI,UAAU,CAKlD;AAED,wBAAgB,aAAa,IAAI,UAAU,CAK1C;AAED,wBAAgB,gBAAgB,IAAI,UAAU,CAK7C;AAED,wBAAgB,QAAQ,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,UAA4B,GAAG,UAAU,CAEtF;AAED,wBAAgB,gBAAgB,IAAI,UAAU,CAE7C;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,GAAG,UAAU,CAGzE;AAED,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAEzD;AAED,wBAAgB,sBAAsB,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAE/D;AAED,wBAAgB,iBAAiB,IAAI,UAAU,CAE9C"}
@@ -0,0 +1,31 @@
1
+ import { CodedError } from 'expo-modules-core';
2
+ import { AppleMusicErrorCode } from '../constants/apple-music-error-codes';
3
+ export function missingDeveloperToken() {
4
+ return new CodedError(AppleMusicErrorCode.missingDeveloperToken, 'Apple Music developer token is required on web. Pass a signed JWT to Auth.authorize(token).');
5
+ }
6
+ export function missingTokens() {
7
+ return new CodedError(AppleMusicErrorCode.permissionDenied, 'Apple Music authorization required. Call Auth.authorize() first.');
8
+ }
9
+ export function permissionDenied() {
10
+ return new CodedError(AppleMusicErrorCode.permissionDenied, 'Apple Music authorization required or subscription needed (403)');
11
+ }
12
+ export function apiError(message, code = AppleMusicErrorCode.error) {
13
+ return new CodedError(code, message);
14
+ }
15
+ export function playlistNotFound() {
16
+ return new CodedError(AppleMusicErrorCode.error, 'Playlist not found in library');
17
+ }
18
+ export function itemNotFound(item, inLibrary) {
19
+ const source = inLibrary ? 'library' : 'catalog';
20
+ return new CodedError(AppleMusicErrorCode.error, `${item} not found in ${source}`);
21
+ }
22
+ export function unknownMediaType(type) {
23
+ return new CodedError(AppleMusicErrorCode.error, `Unknown media type: ${type}`);
24
+ }
25
+ export function unsupportedLibraryType(type) {
26
+ return new CodedError(AppleMusicErrorCode.error, `Unsupported library media type: ${type}`);
27
+ }
28
+ export function noSongsInPlaylist() {
29
+ return new CodedError(AppleMusicErrorCode.error, 'No songs in playlist');
30
+ }
31
+ //# sourceMappingURL=apple-music-errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"apple-music-errors.js","sourceRoot":"","sources":["../../src/web/apple-music-errors.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,EAAE,mBAAmB,EAAE,MAAM,sCAAsC,CAAC;AAE3E,MAAM,UAAU,qBAAqB;IACnC,OAAO,IAAI,UAAU,CACnB,mBAAmB,CAAC,qBAAqB,EACzC,6FAA6F,CAC9F,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,aAAa;IAC3B,OAAO,IAAI,UAAU,CACnB,mBAAmB,CAAC,gBAAgB,EACpC,kEAAkE,CACnE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,IAAI,UAAU,CACnB,mBAAmB,CAAC,gBAAgB,EACpC,iEAAiE,CAClE,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,QAAQ,CAAC,OAAe,EAAE,IAAI,GAAG,mBAAmB,CAAC,KAAK;IACxE,OAAO,IAAI,UAAU,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,gBAAgB;IAC9B,OAAO,IAAI,UAAU,CAAC,mBAAmB,CAAC,KAAK,EAAE,+BAA+B,CAAC,CAAC;AACpF,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,IAAY,EAAE,SAAkB;IAC3D,MAAM,MAAM,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;IACjD,OAAO,IAAI,UAAU,CAAC,mBAAmB,CAAC,KAAK,EAAE,GAAG,IAAI,iBAAiB,MAAM,EAAE,CAAC,CAAC;AACrF,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAC3C,OAAO,IAAI,UAAU,CAAC,mBAAmB,CAAC,KAAK,EAAE,uBAAuB,IAAI,EAAE,CAAC,CAAC;AAClF,CAAC;AAED,MAAM,UAAU,sBAAsB,CAAC,IAAY;IACjD,OAAO,IAAI,UAAU,CAAC,mBAAmB,CAAC,KAAK,EAAE,mCAAmC,IAAI,EAAE,CAAC,CAAC;AAC9F,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC/B,OAAO,IAAI,UAAU,CAAC,mBAAmB,CAAC,KAAK,EAAE,sBAAsB,CAAC,CAAC;AAC3E,CAAC","sourcesContent":["import { CodedError } from 'expo-modules-core';\nimport { AppleMusicErrorCode } from '../constants/apple-music-error-codes';\n\nexport function missingDeveloperToken(): CodedError {\n return new CodedError(\n AppleMusicErrorCode.missingDeveloperToken,\n 'Apple Music developer token is required on web. Pass a signed JWT to Auth.authorize(token).',\n );\n}\n\nexport function missingTokens(): CodedError {\n return new CodedError(\n AppleMusicErrorCode.permissionDenied,\n 'Apple Music authorization required. Call Auth.authorize() first.',\n );\n}\n\nexport function permissionDenied(): CodedError {\n return new CodedError(\n AppleMusicErrorCode.permissionDenied,\n 'Apple Music authorization required or subscription needed (403)',\n );\n}\n\nexport function apiError(message: string, code = AppleMusicErrorCode.error): CodedError {\n return new CodedError(code, message);\n}\n\nexport function playlistNotFound(): CodedError {\n return new CodedError(AppleMusicErrorCode.error, 'Playlist not found in library');\n}\n\nexport function itemNotFound(item: string, inLibrary: boolean): CodedError {\n const source = inLibrary ? 'library' : 'catalog';\n return new CodedError(AppleMusicErrorCode.error, `${item} not found in ${source}`);\n}\n\nexport function unknownMediaType(type: string): CodedError {\n return new CodedError(AppleMusicErrorCode.error, `Unknown media type: ${type}`);\n}\n\nexport function unsupportedLibraryType(type: string): CodedError {\n return new CodedError(AppleMusicErrorCode.error, `Unsupported library media type: ${type}`);\n}\n\nexport function noSongsInPlaylist(): CodedError {\n return new CodedError(AppleMusicErrorCode.error, 'No songs in playlist');\n}\n"]}
@@ -0,0 +1,4 @@
1
+ import type { MusicKitInstance } from './musickit-types';
2
+ /** Music user token from MusicKit JS `authorize()` when it returns a token string. */
3
+ export declare function extractMusicUserToken(music: MusicKitInstance, authorizeResult?: unknown): string | undefined;
4
+ //# sourceMappingURL=extract-music-user-token.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-music-user-token.d.ts","sourceRoot":"","sources":["../../src/web/extract-music-user-token.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,sFAAsF;AACtF,wBAAgB,qBAAqB,CACnC,KAAK,EAAE,gBAAgB,EACvB,eAAe,CAAC,EAAE,OAAO,GACxB,MAAM,GAAG,SAAS,CAYpB"}
@@ -0,0 +1,15 @@
1
+ /** Music user token from MusicKit JS `authorize()` when it returns a token string. */
2
+ export function extractMusicUserToken(music, authorizeResult) {
3
+ if (typeof authorizeResult === 'string') {
4
+ const trimmed = authorizeResult.trim();
5
+ if (trimmed.length > 20 && !trimmed.toLowerCase().includes('authorized')) {
6
+ return trimmed;
7
+ }
8
+ }
9
+ const fromInstance = music.musicUserToken;
10
+ if (typeof fromInstance === 'string' && fromInstance.trim().length > 0) {
11
+ return fromInstance.trim();
12
+ }
13
+ return undefined;
14
+ }
15
+ //# sourceMappingURL=extract-music-user-token.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"extract-music-user-token.js","sourceRoot":"","sources":["../../src/web/extract-music-user-token.ts"],"names":[],"mappings":"AAEA,sFAAsF;AACtF,MAAM,UAAU,qBAAqB,CACnC,KAAuB,EACvB,eAAyB;IAEzB,IAAI,OAAO,eAAe,KAAK,QAAQ,EAAE,CAAC;QACxC,MAAM,OAAO,GAAG,eAAe,CAAC,IAAI,EAAE,CAAC;QACvC,IAAI,OAAO,CAAC,MAAM,GAAG,EAAE,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,YAAY,CAAC,EAAE,CAAC;YACzE,OAAO,OAAO,CAAC;QACjB,CAAC;IACH,CAAC;IACD,MAAM,YAAY,GAAI,KAAqC,CAAC,cAAc,CAAC;IAC3E,IAAI,OAAO,YAAY,KAAK,QAAQ,IAAI,YAAY,CAAC,IAAI,EAAE,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvE,OAAO,YAAY,CAAC,IAAI,EAAE,CAAC;IAC7B,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC","sourcesContent":["import type { MusicKitInstance } from './musickit-types';\n\n/** Music user token from MusicKit JS `authorize()` when it returns a token string. */\nexport function extractMusicUserToken(\n music: MusicKitInstance,\n authorizeResult?: unknown,\n): string | undefined {\n if (typeof authorizeResult === 'string') {\n const trimmed = authorizeResult.trim();\n if (trimmed.length > 20 && !trimmed.toLowerCase().includes('authorized')) {\n return trimmed;\n }\n }\n const fromInstance = (music as { musicUserToken?: string }).musicUserToken;\n if (typeof fromInstance === 'string' && fromInstance.trim().length > 0) {\n return fromInstance.trim();\n }\n return undefined;\n}\n"]}
@@ -0,0 +1,17 @@
1
+ import type { MusicKitInstance } from './musickit-types';
2
+ /** MusicKit JS `authorizationStatus` values (StoreKit). */
3
+ export declare const MusicKitAuthorizationStatus: {
4
+ readonly UNAVAILABLE: -1;
5
+ readonly NOT_DETERMINED: 0;
6
+ readonly DENIED: 1;
7
+ readonly RESTRICTED: 2;
8
+ readonly AUTHORIZED: 3;
9
+ };
10
+ export type AuthStatusValue = 'authorized' | 'denied' | 'notDetermined' | 'restricted' | 'unknown';
11
+ /**
12
+ * Map MusicKit JS authorize() return values and instance flags to bridge `AuthStatus`.
13
+ * `authorize()` may return a music user token string, not a status label.
14
+ */
15
+ export declare function authStatusFromMusicKit(music: MusicKitInstance, authorizeResult?: unknown): AuthStatusValue;
16
+ export declare function authStatusFromAuthorizeError(error: unknown): AuthStatusValue;
17
+ //# sourceMappingURL=map-auth-status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"map-auth-status.d.ts","sourceRoot":"","sources":["../../src/web/map-auth-status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAEzD,2DAA2D;AAC3D,eAAO,MAAM,2BAA2B;;;;;;CAM9B,CAAC;AAEX,MAAM,MAAM,eAAe,GACvB,YAAY,GACZ,QAAQ,GACR,eAAe,GACf,YAAY,GACZ,SAAS,CAAC;AAuBd;;;GAGG;AACH,wBAAgB,sBAAsB,CACpC,KAAK,EAAE,gBAAgB,EACvB,eAAe,CAAC,EAAE,OAAO,GACxB,eAAe,CAqCjB;AAED,wBAAgB,4BAA4B,CAAC,KAAK,EAAE,OAAO,GAAG,eAAe,CAyB5E"}
@@ -0,0 +1,85 @@
1
+ /** MusicKit JS `authorizationStatus` values (StoreKit). */
2
+ export const MusicKitAuthorizationStatus = {
3
+ UNAVAILABLE: -1,
4
+ NOT_DETERMINED: 0,
5
+ DENIED: 1,
6
+ RESTRICTED: 2,
7
+ AUTHORIZED: 3,
8
+ };
9
+ /** MusicKit JS `authorize()` resolves with a music user token string on success. */
10
+ function isMusicUserTokenString(value) {
11
+ const trimmed = value.trim();
12
+ return trimmed.length > 20 && !trimmed.toLowerCase().includes('authorized');
13
+ }
14
+ function fromAuthorizationStatus(status) {
15
+ switch (status) {
16
+ case MusicKitAuthorizationStatus.AUTHORIZED:
17
+ return 'authorized';
18
+ case MusicKitAuthorizationStatus.DENIED:
19
+ return 'denied';
20
+ case MusicKitAuthorizationStatus.RESTRICTED:
21
+ return 'restricted';
22
+ case MusicKitAuthorizationStatus.NOT_DETERMINED:
23
+ return 'notDetermined';
24
+ default:
25
+ return 'unknown';
26
+ }
27
+ }
28
+ /**
29
+ * Map MusicKit JS authorize() return values and instance flags to bridge `AuthStatus`.
30
+ * `authorize()` may return a music user token string, not a status label.
31
+ */
32
+ export function authStatusFromMusicKit(music, authorizeResult) {
33
+ if (music.isAuthorized) {
34
+ return 'authorized';
35
+ }
36
+ if (music.isRestricted) {
37
+ return 'restricted';
38
+ }
39
+ if (typeof authorizeResult === 'number') {
40
+ return fromAuthorizationStatus(authorizeResult);
41
+ }
42
+ if (typeof authorizeResult === 'string') {
43
+ const value = authorizeResult.toLowerCase();
44
+ if (value.includes('authorized')) {
45
+ return 'authorized';
46
+ }
47
+ if (value.includes('denied') || value.includes('not_authorized')) {
48
+ return 'denied';
49
+ }
50
+ if (value.includes('restricted')) {
51
+ return 'restricted';
52
+ }
53
+ if (value.includes('not_determined')) {
54
+ return 'notDetermined';
55
+ }
56
+ if (isMusicUserTokenString(authorizeResult)) {
57
+ return 'authorized';
58
+ }
59
+ }
60
+ if (typeof music.authorizationStatus === 'number') {
61
+ return fromAuthorizationStatus(music.authorizationStatus);
62
+ }
63
+ return 'unknown';
64
+ }
65
+ export function authStatusFromAuthorizeError(error) {
66
+ const message = error instanceof Error
67
+ ? error.message
68
+ : typeof error === 'string'
69
+ ? error
70
+ : '';
71
+ const normalized = message.toLowerCase();
72
+ if (normalized.includes('restricted') ||
73
+ normalized.includes('subscription') ||
74
+ normalized.includes('no_subscription')) {
75
+ return 'restricted';
76
+ }
77
+ if (normalized.includes('cancel') ||
78
+ normalized.includes('denied') ||
79
+ normalized.includes('unauthorized') ||
80
+ normalized.includes('authorization_error')) {
81
+ return 'denied';
82
+ }
83
+ return 'unknown';
84
+ }
85
+ //# sourceMappingURL=map-auth-status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"map-auth-status.js","sourceRoot":"","sources":["../../src/web/map-auth-status.ts"],"names":[],"mappings":"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","sourcesContent":["import type { MusicKitInstance } from './musickit-types';\n\n/** MusicKit JS `authorizationStatus` values (StoreKit). */\nexport const MusicKitAuthorizationStatus = {\n UNAVAILABLE: -1,\n NOT_DETERMINED: 0,\n DENIED: 1,\n RESTRICTED: 2,\n AUTHORIZED: 3,\n} as const;\n\nexport type AuthStatusValue =\n | 'authorized'\n | 'denied'\n | 'notDetermined'\n | 'restricted'\n | 'unknown';\n\n/** MusicKit JS `authorize()` resolves with a music user token string on success. */\nfunction isMusicUserTokenString(value: string): boolean {\n const trimmed = value.trim();\n return trimmed.length > 20 && !trimmed.toLowerCase().includes('authorized');\n}\n\nfunction fromAuthorizationStatus(status: number): AuthStatusValue {\n switch (status) {\n case MusicKitAuthorizationStatus.AUTHORIZED:\n return 'authorized';\n case MusicKitAuthorizationStatus.DENIED:\n return 'denied';\n case MusicKitAuthorizationStatus.RESTRICTED:\n return 'restricted';\n case MusicKitAuthorizationStatus.NOT_DETERMINED:\n return 'notDetermined';\n default:\n return 'unknown';\n }\n}\n\n/**\n * Map MusicKit JS authorize() return values and instance flags to bridge `AuthStatus`.\n * `authorize()` may return a music user token string, not a status label.\n */\nexport function authStatusFromMusicKit(\n music: MusicKitInstance,\n authorizeResult?: unknown,\n): AuthStatusValue {\n if (music.isAuthorized) {\n return 'authorized';\n }\n\n if (music.isRestricted) {\n return 'restricted';\n }\n\n if (typeof authorizeResult === 'number') {\n return fromAuthorizationStatus(authorizeResult);\n }\n\n if (typeof authorizeResult === 'string') {\n const value = authorizeResult.toLowerCase();\n if (value.includes('authorized')) {\n return 'authorized';\n }\n if (value.includes('denied') || value.includes('not_authorized')) {\n return 'denied';\n }\n if (value.includes('restricted')) {\n return 'restricted';\n }\n if (value.includes('not_determined')) {\n return 'notDetermined';\n }\n if (isMusicUserTokenString(authorizeResult)) {\n return 'authorized';\n }\n }\n\n if (typeof music.authorizationStatus === 'number') {\n return fromAuthorizationStatus(music.authorizationStatus);\n }\n\n return 'unknown';\n}\n\nexport function authStatusFromAuthorizeError(error: unknown): AuthStatusValue {\n const message =\n error instanceof Error\n ? error.message\n : typeof error === 'string'\n ? error\n : '';\n\n const normalized = message.toLowerCase();\n if (\n normalized.includes('restricted') ||\n normalized.includes('subscription') ||\n normalized.includes('no_subscription')\n ) {\n return 'restricted';\n }\n if (\n normalized.includes('cancel') ||\n normalized.includes('denied') ||\n normalized.includes('unauthorized') ||\n normalized.includes('authorization_error')\n ) {\n return 'denied';\n }\n return 'unknown';\n}\n"]}
@@ -0,0 +1,18 @@
1
+ import type { MusicKitApiResponse, MusicKitInstance } from './musickit-types';
2
+ type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';
3
+ /**
4
+ * Normalize Apple Music API paths for MusicKit JS.
5
+ * Keep the `/v1` prefix — MusicKit's session base is `https://api.music.apple.com`
6
+ * (no version in the host path). Stripping `/v1` produces invalid URLs like
7
+ * `https://api.music.apple.com/catalog/...` that fail CORS / 405.
8
+ */
9
+ export declare function toMusicKitApiPath(appleMusicApiPath: string): string;
10
+ /** Reject Apple Music API error payloads (same policy as native REST clients). */
11
+ export declare function throwIfApiErrors(json: MusicKitApiResponse): void;
12
+ /** APISession returns `{ data: <Apple Music JSON body> }`; normalize to API shape. */
13
+ export declare function unwrapMusicKitApiResponse(raw: unknown): MusicKitApiResponse;
14
+ export declare function parseStorefrontId(json: MusicKitApiResponse): string | null;
15
+ export declare function storefrontIdFromInstance(music: MusicKitInstance): string | null;
16
+ export declare function musicKitApiRequest(music: MusicKitInstance, method: HttpMethod, path: string, query?: Record<string, string>, body?: Record<string, unknown>, musicUserToken?: string): Promise<MusicKitApiResponse>;
17
+ export {};
18
+ //# sourceMappingURL=music-kit-api.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"music-kit-api.d.ts","sourceRoot":"","sources":["../../src/web/music-kit-api.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAC;AAG9E,KAAK,UAAU,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,CAAC;AAWpD;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,iBAAiB,EAAE,MAAM,GAAG,MAAM,CAYnE;AAYD,kFAAkF;AAClF,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,mBAAmB,GAAG,IAAI,CAWhE;AAED,sFAAsF;AACtF,wBAAgB,yBAAyB,CAAC,GAAG,EAAE,OAAO,GAAG,mBAAmB,CAgB3E;AAED,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,mBAAmB,GAAG,MAAM,GAAG,IAAI,CAe1E;AAsBD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,gBAAgB,GAAG,MAAM,GAAG,IAAI,CAM/E;AAED,wBAAsB,kBAAkB,CACtC,KAAK,EAAE,gBAAgB,EACvB,MAAM,EAAE,UAAU,EAClB,IAAI,EAAE,MAAM,EACZ,KAAK,GAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAM,EAClC,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC9B,cAAc,CAAC,EAAE,MAAM,GACtB,OAAO,CAAC,mBAAmB,CAAC,CA0B9B"}
@@ -0,0 +1,120 @@
1
+ import * as errors from './apple-music-errors';
2
+ /**
3
+ * Normalize Apple Music API paths for MusicKit JS.
4
+ * Keep the `/v1` prefix — MusicKit's session base is `https://api.music.apple.com`
5
+ * (no version in the host path). Stripping `/v1` produces invalid URLs like
6
+ * `https://api.music.apple.com/catalog/...` that fail CORS / 405.
7
+ */
8
+ export function toMusicKitApiPath(appleMusicApiPath) {
9
+ const trimmed = appleMusicApiPath.trim();
10
+ if (trimmed.startsWith('/v1/')) {
11
+ return trimmed;
12
+ }
13
+ if (trimmed.startsWith('v1/')) {
14
+ return `/${trimmed}`;
15
+ }
16
+ if (trimmed.startsWith('/')) {
17
+ return `/v1${trimmed}`;
18
+ }
19
+ return `/v1/${trimmed}`;
20
+ }
21
+ function isMusicKitApiBody(value) {
22
+ if (!value || typeof value !== 'object') {
23
+ return false;
24
+ }
25
+ const record = value;
26
+ return (record.data !== undefined || record.results !== undefined || record.errors !== undefined);
27
+ }
28
+ /** Reject Apple Music API error payloads (same policy as native REST clients). */
29
+ export function throwIfApiErrors(json) {
30
+ const apiErrors = json.errors;
31
+ if (!Array.isArray(apiErrors) || apiErrors.length === 0) {
32
+ return;
33
+ }
34
+ const first = apiErrors[0];
35
+ const detail = (first && typeof first.detail === 'string' && first.detail) ||
36
+ (first && typeof first.title === 'string' && first.title) ||
37
+ 'Apple Music API error';
38
+ throw errors.apiError(detail);
39
+ }
40
+ /** APISession returns `{ data: <Apple Music JSON body> }`; normalize to API shape. */
41
+ export function unwrapMusicKitApiResponse(raw) {
42
+ if (!raw || typeof raw !== 'object') {
43
+ throw errors.apiError('Invalid MusicKit API response');
44
+ }
45
+ const envelope = raw;
46
+ const inner = envelope.data;
47
+ if (inner && typeof inner === 'object' && !Array.isArray(inner) && isMusicKitApiBody(inner)) {
48
+ const body = inner;
49
+ throwIfApiErrors(body);
50
+ return body;
51
+ }
52
+ if (isMusicKitApiBody(envelope)) {
53
+ throwIfApiErrors(envelope);
54
+ return envelope;
55
+ }
56
+ throw errors.apiError('Invalid MusicKit API response');
57
+ }
58
+ export function parseStorefrontId(json) {
59
+ const data = json.data;
60
+ if (Array.isArray(data) && data.length > 0) {
61
+ const id = data[0].id;
62
+ if (typeof id === 'string' && id.length > 0) {
63
+ return id.toLowerCase();
64
+ }
65
+ }
66
+ if (data && typeof data === 'object' && !Array.isArray(data)) {
67
+ const id = data.id;
68
+ if (typeof id === 'string' && id.length > 0) {
69
+ return id.toLowerCase();
70
+ }
71
+ }
72
+ return null;
73
+ }
74
+ function resolveMusicRequest(music) {
75
+ const api = music.api;
76
+ if (typeof api === 'function') {
77
+ return api.bind(music.api);
78
+ }
79
+ if (api && typeof api === 'object') {
80
+ if (typeof api.music === 'function') {
81
+ return api.music.bind(api);
82
+ }
83
+ const v3 = api.v3;
84
+ if (v3 && typeof v3.music === 'function') {
85
+ return v3.music.bind(v3);
86
+ }
87
+ }
88
+ throw new Error('MusicKit API is not available');
89
+ }
90
+ export function storefrontIdFromInstance(music) {
91
+ const id = music.storefrontId;
92
+ if (typeof id === 'string' && id.length > 0) {
93
+ return id.toLowerCase();
94
+ }
95
+ return null;
96
+ }
97
+ export async function musicKitApiRequest(music, method, path, query = {}, body, musicUserToken) {
98
+ const request = resolveMusicRequest(music);
99
+ const mkPath = toMusicKitApiPath(path);
100
+ const headers = {};
101
+ if (body) {
102
+ headers['Content-Type'] = 'application/json';
103
+ }
104
+ if (musicUserToken && path.startsWith('/v1/me/')) {
105
+ headers['Music-User-Token'] = musicUserToken;
106
+ }
107
+ const sessionOptions = {
108
+ method,
109
+ };
110
+ if (body || Object.keys(headers).length > 0) {
111
+ sessionOptions.fetchOptions = {
112
+ method,
113
+ headers,
114
+ ...(body ? { body: JSON.stringify(body) } : {}),
115
+ };
116
+ }
117
+ const raw = await request(mkPath, query, sessionOptions);
118
+ return unwrapMusicKitApiResponse(raw);
119
+ }
120
+ //# sourceMappingURL=music-kit-api.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"music-kit-api.js","sourceRoot":"","sources":["../../src/web/music-kit-api.ts"],"names":[],"mappings":"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","sourcesContent":["import type { AppleMusicApiResource } from '../mappers/apple-music-json-mapper';\nimport type { MusicKitApiResponse, MusicKitInstance } from './musickit-types';\nimport * as errors from './apple-music-errors';\n\ntype HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE';\n\ntype MusicKitRequestFn = (\n path: string,\n query?: Record<string, string>,\n options?: {\n method?: string;\n fetchOptions?: RequestInit;\n },\n) => Promise<unknown>;\n\n/**\n * Normalize Apple Music API paths for MusicKit JS.\n * Keep the `/v1` prefix — MusicKit's session base is `https://api.music.apple.com`\n * (no version in the host path). Stripping `/v1` produces invalid URLs like\n * `https://api.music.apple.com/catalog/...` that fail CORS / 405.\n */\nexport function toMusicKitApiPath(appleMusicApiPath: string): string {\n const trimmed = appleMusicApiPath.trim();\n if (trimmed.startsWith('/v1/')) {\n return trimmed;\n }\n if (trimmed.startsWith('v1/')) {\n return `/${trimmed}`;\n }\n if (trimmed.startsWith('/')) {\n return `/v1${trimmed}`;\n }\n return `/v1/${trimmed}`;\n}\n\nfunction isMusicKitApiBody(value: unknown): value is MusicKitApiResponse {\n if (!value || typeof value !== 'object') {\n return false;\n }\n const record = value as Record<string, unknown>;\n return (\n record.data !== undefined || record.results !== undefined || record.errors !== undefined\n );\n}\n\n/** Reject Apple Music API error payloads (same policy as native REST clients). */\nexport function throwIfApiErrors(json: MusicKitApiResponse): void {\n const apiErrors = json.errors;\n if (!Array.isArray(apiErrors) || apiErrors.length === 0) {\n return;\n }\n const first = apiErrors[0];\n const detail =\n (first && typeof first.detail === 'string' && first.detail) ||\n (first && typeof (first as { title?: string }).title === 'string' && (first as { title: string }).title) ||\n 'Apple Music API error';\n throw errors.apiError(detail);\n}\n\n/** APISession returns `{ data: <Apple Music JSON body> }`; normalize to API shape. */\nexport function unwrapMusicKitApiResponse(raw: unknown): MusicKitApiResponse {\n if (!raw || typeof raw !== 'object') {\n throw errors.apiError('Invalid MusicKit API response');\n }\n const envelope = raw as Record<string, unknown>;\n const inner = envelope.data;\n if (inner && typeof inner === 'object' && !Array.isArray(inner) && isMusicKitApiBody(inner)) {\n const body = inner;\n throwIfApiErrors(body);\n return body;\n }\n if (isMusicKitApiBody(envelope)) {\n throwIfApiErrors(envelope);\n return envelope;\n }\n throw errors.apiError('Invalid MusicKit API response');\n}\n\nexport function parseStorefrontId(json: MusicKitApiResponse): string | null {\n const data = json.data;\n if (Array.isArray(data) && data.length > 0) {\n const id = (data[0] as AppleMusicApiResource).id;\n if (typeof id === 'string' && id.length > 0) {\n return id.toLowerCase();\n }\n }\n if (data && typeof data === 'object' && !Array.isArray(data)) {\n const id = (data as AppleMusicApiResource).id;\n if (typeof id === 'string' && id.length > 0) {\n return id.toLowerCase();\n }\n }\n return null;\n}\n\nfunction resolveMusicRequest(music: MusicKitInstance): MusicKitRequestFn {\n const api = music.api as Record<string, unknown> | MusicKitRequestFn;\n\n if (typeof api === 'function') {\n return api.bind(music.api);\n }\n\n if (api && typeof api === 'object') {\n if (typeof api.music === 'function') {\n return (api.music as MusicKitRequestFn).bind(api);\n }\n const v3 = api.v3 as Record<string, unknown> | undefined;\n if (v3 && typeof v3.music === 'function') {\n return (v3.music as MusicKitRequestFn).bind(v3);\n }\n }\n\n throw new Error('MusicKit API is not available');\n}\n\nexport function storefrontIdFromInstance(music: MusicKitInstance): string | null {\n const id = music.storefrontId;\n if (typeof id === 'string' && id.length > 0) {\n return id.toLowerCase();\n }\n return null;\n}\n\nexport async function musicKitApiRequest(\n music: MusicKitInstance,\n method: HttpMethod,\n path: string,\n query: Record<string, string> = {},\n body?: Record<string, unknown>,\n musicUserToken?: string,\n): Promise<MusicKitApiResponse> {\n const request = resolveMusicRequest(music);\n const mkPath = toMusicKitApiPath(path);\n\n const headers: Record<string, string> = {};\n if (body) {\n headers['Content-Type'] = 'application/json';\n }\n if (musicUserToken && path.startsWith('/v1/me/')) {\n headers['Music-User-Token'] = musicUserToken;\n }\n\n const sessionOptions: { method?: string; fetchOptions?: RequestInit } = {\n method,\n };\n\n if (body || Object.keys(headers).length > 0) {\n sessionOptions.fetchOptions = {\n method,\n headers,\n ...(body ? { body: JSON.stringify(body) } : {}),\n };\n }\n\n const raw = await request(mkPath, query, sessionOptions);\n return unwrapMusicKitApiResponse(raw);\n}\n"]}
@@ -0,0 +1,70 @@
1
+ /** Minimal MusicKit JS v3 surface used by the web bridge. */
2
+ export type MusicKitAuthorizeStatus = string;
3
+ export interface MusicKitMediaItem {
4
+ id: string;
5
+ type: string;
6
+ attributes?: Record<string, unknown>;
7
+ }
8
+ export interface MusicKitPlayer {
9
+ nowPlayingItem: MusicKitMediaItem | null;
10
+ currentPlaybackTime: number;
11
+ currentPlaybackDuration: number;
12
+ playbackState: string;
13
+ isPlaying: boolean;
14
+ }
15
+ export interface MusicKitApiResponse {
16
+ data?: unknown;
17
+ results?: Record<string, {
18
+ data?: unknown[];
19
+ }>;
20
+ errors?: {
21
+ detail?: string;
22
+ }[];
23
+ }
24
+ export interface MusicKitInstance {
25
+ isAuthorized: boolean;
26
+ /** Set after authorize — country code (e.g. `us`). Prefer over REST when present. */
27
+ storefrontId?: string;
28
+ /** Present on MusicKit JS v3 — numeric {@link MusicKitAuthorizationStatus}. */
29
+ authorizationStatus?: number;
30
+ isRestricted?: boolean;
31
+ authorize(): Promise<MusicKitAuthorizeStatus>;
32
+ play(): Promise<void>;
33
+ pause(): Promise<void>;
34
+ skipToNextItem(): Promise<void>;
35
+ skipToPreviousItem(): Promise<void>;
36
+ seekToTime(time: number): Promise<void>;
37
+ restart(): Promise<void>;
38
+ setQueue(options: Record<string, unknown>): Promise<void>;
39
+ queue: {
40
+ items?: MusicKitMediaItem[];
41
+ };
42
+ player: MusicKitPlayer;
43
+ nowPlayingItem: MusicKitMediaItem | null;
44
+ currentPlaybackTime: number;
45
+ isPlaying: boolean;
46
+ addEventListener(type: string, listener: () => void): void;
47
+ removeEventListener(type: string, listener: () => void): void;
48
+ api: {
49
+ music(path: string, query?: Record<string, string>, options?: {
50
+ method?: string;
51
+ fetchOptions?: RequestInit;
52
+ }): Promise<unknown>;
53
+ };
54
+ }
55
+ export interface MusicKitStatic {
56
+ configure(options: {
57
+ developerToken: string;
58
+ app: {
59
+ name: string;
60
+ build: string;
61
+ };
62
+ }): Promise<MusicKitInstance>;
63
+ getInstance(): MusicKitInstance;
64
+ }
65
+ declare global {
66
+ interface Window {
67
+ MusicKit?: MusicKitStatic;
68
+ }
69
+ }
70
+ //# sourceMappingURL=musickit-types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"musickit-types.d.ts","sourceRoot":"","sources":["../../src/web/musickit-types.ts"],"names":[],"mappings":"AAAA,6DAA6D;AAE7D,MAAM,MAAM,uBAAuB,GAAG,MAAM,CAAC;AAE7C,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CACtC;AAED,MAAM,WAAW,cAAc;IAC7B,cAAc,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,uBAAuB,EAAE,MAAM,CAAC;IAChC,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE;QAAE,IAAI,CAAC,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC,CAAC;IAC/C,MAAM,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE,EAAE,CAAC;CAChC;AAED,MAAM,WAAW,gBAAgB;IAC/B,YAAY,EAAE,OAAO,CAAC;IACtB,qFAAqF;IACrF,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,+EAA+E;IAC/E,mBAAmB,CAAC,EAAE,MAAM,CAAC;IAC7B,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,SAAS,IAAI,OAAO,CAAC,uBAAuB,CAAC,CAAC;IAC9C,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACtB,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACvB,cAAc,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,kBAAkB,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACpC,UAAU,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACxC,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAC1D,KAAK,EAAE;QAAE,KAAK,CAAC,EAAE,iBAAiB,EAAE,CAAA;KAAE,CAAC;IACvC,MAAM,EAAE,cAAc,CAAC;IACvB,cAAc,EAAE,iBAAiB,GAAG,IAAI,CAAC;IACzC,mBAAmB,EAAE,MAAM,CAAC;IAC5B,SAAS,EAAE,OAAO,CAAC;IACnB,gBAAgB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC3D,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC9D,GAAG,EAAE;QACH,KAAK,CACH,IAAI,EAAE,MAAM,EACZ,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC9B,OAAO,CAAC,EAAE;YACR,MAAM,CAAC,EAAE,MAAM,CAAC;YAChB,YAAY,CAAC,EAAE,WAAW,CAAC;SAC5B,GACA,OAAO,CAAC,OAAO,CAAC,CAAC;KACrB,CAAC;CACH;AAED,MAAM,WAAW,cAAc;IAC7B,SAAS,CAAC,OAAO,EAAE;QACjB,cAAc,EAAE,MAAM,CAAC;QACvB,GAAG,EAAE;YAAE,IAAI,EAAE,MAAM,CAAC;YAAC,KAAK,EAAE,MAAM,CAAA;SAAE,CAAC;KACtC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC9B,WAAW,IAAI,gBAAgB,CAAC;CACjC;AAED,OAAO,CAAC,MAAM,CAAC;IACb,UAAU,MAAM;QACd,QAAQ,CAAC,EAAE,cAAc,CAAC;KAC3B;CACF"}
@@ -0,0 +1,3 @@
1
+ /** Minimal MusicKit JS v3 surface used by the web bridge. */
2
+ export {};
3
+ //# sourceMappingURL=musickit-types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"musickit-types.js","sourceRoot":"","sources":["../../src/web/musickit-types.ts"],"names":[],"mappings":"AAAA,6DAA6D","sourcesContent":["/** Minimal MusicKit JS v3 surface used by the web bridge. */\n\nexport type MusicKitAuthorizeStatus = string;\n\nexport interface MusicKitMediaItem {\n id: string;\n type: string;\n attributes?: Record<string, unknown>;\n}\n\nexport interface MusicKitPlayer {\n nowPlayingItem: MusicKitMediaItem | null;\n currentPlaybackTime: number;\n currentPlaybackDuration: number;\n playbackState: string;\n isPlaying: boolean;\n}\n\nexport interface MusicKitApiResponse {\n data?: unknown;\n results?: Record<string, { data?: unknown[] }>;\n errors?: { detail?: string }[];\n}\n\nexport interface MusicKitInstance {\n isAuthorized: boolean;\n /** Set after authorize — country code (e.g. `us`). Prefer over REST when present. */\n storefrontId?: string;\n /** Present on MusicKit JS v3 — numeric {@link MusicKitAuthorizationStatus}. */\n authorizationStatus?: number;\n isRestricted?: boolean;\n authorize(): Promise<MusicKitAuthorizeStatus>;\n play(): Promise<void>;\n pause(): Promise<void>;\n skipToNextItem(): Promise<void>;\n skipToPreviousItem(): Promise<void>;\n seekToTime(time: number): Promise<void>;\n restart(): Promise<void>;\n setQueue(options: Record<string, unknown>): Promise<void>;\n queue: { items?: MusicKitMediaItem[] };\n player: MusicKitPlayer;\n nowPlayingItem: MusicKitMediaItem | null;\n currentPlaybackTime: number;\n isPlaying: boolean;\n addEventListener(type: string, listener: () => void): void;\n removeEventListener(type: string, listener: () => void): void;\n api: {\n music(\n path: string,\n query?: Record<string, string>,\n options?: {\n method?: string;\n fetchOptions?: RequestInit;\n },\n ): Promise<unknown>;\n };\n}\n\nexport interface MusicKitStatic {\n configure(options: {\n developerToken: string;\n app: { name: string; build: string };\n }): Promise<MusicKitInstance>;\n getInstance(): MusicKitInstance;\n}\n\ndeclare global {\n interface Window {\n MusicKit?: MusicKitStatic;\n }\n}\n"]}
@@ -0,0 +1,2 @@
1
+ export { normalizePaginationOptions as paginationFromMap } from '../api/pagination';
2
+ //# sourceMappingURL=pagination.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.d.ts","sourceRoot":"","sources":["../../src/web/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,IAAI,iBAAiB,EAAE,MAAM,mBAAmB,CAAC"}
@@ -0,0 +1,2 @@
1
+ export { normalizePaginationOptions as paginationFromMap } from '../api/pagination';
2
+ //# sourceMappingURL=pagination.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"pagination.js","sourceRoot":"","sources":["../../src/web/pagination.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,0BAA0B,IAAI,iBAAiB,EAAE,MAAM,mBAAmB,CAAC","sourcesContent":["export { normalizePaginationOptions as paginationFromMap } from '../api/pagination';\n"]}