@ansango/lastfm-api 3.4.0 → 3.6.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 (623) hide show
  1. package/CHANGELOG.md +65 -0
  2. package/README.md +254 -21
  3. package/dist/cache/index.d.ts +7 -0
  4. package/dist/cache/index.d.ts.map +1 -0
  5. package/dist/cache/index.js +7 -0
  6. package/dist/cache/index.js.map +1 -0
  7. package/dist/cache/interface.d.ts +57 -0
  8. package/dist/cache/interface.d.ts.map +1 -0
  9. package/dist/cache/interface.js +5 -0
  10. package/dist/cache/interface.js.map +1 -0
  11. package/dist/cache/manager.d.ts +19 -0
  12. package/dist/cache/manager.d.ts.map +1 -0
  13. package/dist/cache/manager.js +63 -0
  14. package/dist/cache/manager.js.map +1 -0
  15. package/dist/cache/schemas.d.ts +15 -0
  16. package/dist/cache/schemas.d.ts.map +1 -0
  17. package/dist/cache/schemas.js +13 -0
  18. package/dist/cache/schemas.js.map +1 -0
  19. package/dist/cache/service.d.ts +13 -0
  20. package/dist/cache/service.d.ts.map +1 -0
  21. package/dist/cache/service.js +12 -0
  22. package/dist/cache/service.js.map +1 -0
  23. package/dist/cache/stores/memory.d.ts +33 -0
  24. package/dist/cache/stores/memory.d.ts.map +1 -0
  25. package/dist/cache/stores/memory.js +85 -0
  26. package/dist/cache/stores/memory.js.map +1 -0
  27. package/dist/cache/stores/storage.d.ts +42 -0
  28. package/dist/cache/stores/storage.d.ts.map +1 -0
  29. package/dist/cache/stores/storage.js +109 -0
  30. package/dist/cache/stores/storage.js.map +1 -0
  31. package/dist/client.d.ts +12 -1
  32. package/dist/client.d.ts.map +1 -1
  33. package/dist/client.js +21 -1
  34. package/dist/client.js.map +1 -1
  35. package/dist/config.d.ts +4 -0
  36. package/dist/config.d.ts.map +1 -1
  37. package/dist/config.js +13 -0
  38. package/dist/config.js.map +1 -1
  39. package/dist/core/canonical-methods.d.ts +25 -0
  40. package/dist/core/canonical-methods.d.ts.map +1 -0
  41. package/dist/core/canonical-methods.js +88 -0
  42. package/dist/core/canonical-methods.js.map +1 -0
  43. package/dist/core/client.d.ts +33 -0
  44. package/dist/core/client.d.ts.map +1 -0
  45. package/dist/core/client.js +48 -0
  46. package/dist/core/client.js.map +1 -0
  47. package/dist/core/index.d.ts +6 -0
  48. package/dist/core/index.d.ts.map +1 -0
  49. package/dist/core/index.js +6 -0
  50. package/dist/core/index.js.map +1 -0
  51. package/dist/core/pagination.d.ts +59 -0
  52. package/dist/core/pagination.d.ts.map +1 -0
  53. package/dist/core/pagination.js +93 -0
  54. package/dist/core/pagination.js.map +1 -0
  55. package/dist/core/schemas/album.schemas.d.ts.map +1 -0
  56. package/dist/{services → core/schemas}/album.schemas.js +1 -1
  57. package/dist/core/schemas/album.schemas.js.map +1 -0
  58. package/dist/core/schemas/artist.schemas.d.ts.map +1 -0
  59. package/dist/{services → core/schemas}/artist.schemas.js +1 -1
  60. package/dist/core/schemas/artist.schemas.js.map +1 -0
  61. package/dist/core/schemas/auth.schemas.d.ts.map +1 -0
  62. package/dist/core/schemas/auth.schemas.js.map +1 -0
  63. package/dist/core/schemas/base/base.entities.schemas.d.ts.map +1 -0
  64. package/dist/core/schemas/base/base.entities.schemas.js.map +1 -0
  65. package/dist/core/schemas/base/base.entity-names.schemas.d.ts.map +1 -0
  66. package/dist/core/schemas/base/base.entity-names.schemas.js.map +1 -0
  67. package/dist/core/schemas/base/base.metadata.schemas.d.ts.map +1 -0
  68. package/dist/core/schemas/base/base.metadata.schemas.js.map +1 -0
  69. package/dist/core/schemas/base/base.pagination.schemas.d.ts.map +1 -0
  70. package/dist/core/schemas/base/base.pagination.schemas.js.map +1 -0
  71. package/dist/core/schemas/base/base.primitives.schemas.d.ts.map +1 -0
  72. package/dist/core/schemas/base/base.primitives.schemas.js.map +1 -0
  73. package/dist/core/schemas/base/index.d.ts.map +1 -0
  74. package/dist/core/schemas/base/index.js.map +1 -0
  75. package/dist/core/schemas/chart.schemas.d.ts.map +1 -0
  76. package/dist/{services → core/schemas}/chart.schemas.js +1 -1
  77. package/dist/core/schemas/chart.schemas.js.map +1 -0
  78. package/dist/core/schemas/geo.schemas.d.ts.map +1 -0
  79. package/dist/{services → core/schemas}/geo.schemas.js +1 -1
  80. package/dist/core/schemas/geo.schemas.js.map +1 -0
  81. package/dist/core/schemas/index.d.ts +11 -0
  82. package/dist/core/schemas/index.d.ts.map +1 -0
  83. package/dist/core/schemas/index.js +11 -0
  84. package/dist/core/schemas/index.js.map +1 -0
  85. package/dist/core/schemas/library.schemas.d.ts.map +1 -0
  86. package/dist/{services → core/schemas}/library.schemas.js +1 -1
  87. package/dist/core/schemas/library.schemas.js.map +1 -0
  88. package/dist/core/schemas/tag.schemas.d.ts.map +1 -0
  89. package/dist/{services → core/schemas}/tag.schemas.js +1 -1
  90. package/dist/core/schemas/tag.schemas.js.map +1 -0
  91. package/dist/core/schemas/track.schemas.d.ts.map +1 -0
  92. package/dist/{services → core/schemas}/track.schemas.js +1 -1
  93. package/dist/core/schemas/track.schemas.js.map +1 -0
  94. package/dist/core/schemas/user.schemas.d.ts.map +1 -0
  95. package/dist/{services → core/schemas}/user.schemas.js +1 -1
  96. package/dist/core/schemas/user.schemas.js.map +1 -0
  97. package/dist/{services → core/services}/album.d.ts +2 -2
  98. package/dist/core/services/album.d.ts.map +1 -0
  99. package/dist/{services → core/services}/album.js +5 -5
  100. package/dist/core/services/album.js.map +1 -0
  101. package/dist/{services → core/services}/artist.d.ts +2 -2
  102. package/dist/core/services/artist.d.ts.map +1 -0
  103. package/dist/{services → core/services}/artist.js +9 -9
  104. package/dist/core/services/artist.js.map +1 -0
  105. package/dist/{services → core/services}/auth.d.ts +2 -2
  106. package/dist/core/services/auth.d.ts.map +1 -0
  107. package/dist/{services → core/services}/auth.js +1 -1
  108. package/dist/core/services/auth.js.map +1 -0
  109. package/dist/{services → core/services}/chart.d.ts +2 -2
  110. package/dist/core/services/chart.d.ts.map +1 -0
  111. package/dist/core/services/chart.js +9 -0
  112. package/dist/core/services/chart.js.map +1 -0
  113. package/dist/{services → core/services}/geo.d.ts +2 -2
  114. package/dist/core/services/geo.d.ts.map +1 -0
  115. package/dist/core/services/geo.js +8 -0
  116. package/dist/core/services/geo.js.map +1 -0
  117. package/dist/core/services/index.d.ts +10 -0
  118. package/dist/core/services/index.d.ts.map +1 -0
  119. package/dist/core/services/index.js +10 -0
  120. package/dist/core/services/index.js.map +1 -0
  121. package/dist/{services → core/services}/library.d.ts +2 -2
  122. package/dist/core/services/library.d.ts.map +1 -0
  123. package/dist/core/services/library.js +7 -0
  124. package/dist/core/services/library.js.map +1 -0
  125. package/dist/{services → core/services}/tag.d.ts +2 -2
  126. package/dist/core/services/tag.d.ts.map +1 -0
  127. package/dist/{services → core/services}/tag.js +8 -8
  128. package/dist/core/services/tag.js.map +1 -0
  129. package/dist/{services → core/services}/track.d.ts +2 -2
  130. package/dist/core/services/track.d.ts.map +1 -0
  131. package/dist/{services → core/services}/track.js +7 -7
  132. package/dist/core/services/track.js.map +1 -0
  133. package/dist/{services → core/services}/track.utils.d.ts +2 -2
  134. package/dist/core/services/track.utils.d.ts.map +1 -0
  135. package/dist/core/services/track.utils.js.map +1 -0
  136. package/dist/{services → core/services}/user.d.ts +2 -2
  137. package/dist/core/services/user.d.ts.map +1 -0
  138. package/dist/core/services/user.js +19 -0
  139. package/dist/core/services/user.js.map +1 -0
  140. package/dist/entrypoints/album.d.ts +3 -3
  141. package/dist/entrypoints/album.d.ts.map +1 -1
  142. package/dist/entrypoints/album.js +2 -2
  143. package/dist/entrypoints/album.js.map +1 -1
  144. package/dist/entrypoints/album.schemas.d.ts +2 -1
  145. package/dist/entrypoints/album.schemas.d.ts.map +1 -1
  146. package/dist/entrypoints/album.schemas.js +1 -2
  147. package/dist/entrypoints/album.schemas.js.map +1 -1
  148. package/dist/entrypoints/artist.d.ts +3 -3
  149. package/dist/entrypoints/artist.d.ts.map +1 -1
  150. package/dist/entrypoints/artist.js +2 -2
  151. package/dist/entrypoints/artist.js.map +1 -1
  152. package/dist/entrypoints/artist.schemas.d.ts +2 -1
  153. package/dist/entrypoints/artist.schemas.d.ts.map +1 -1
  154. package/dist/entrypoints/artist.schemas.js +1 -2
  155. package/dist/entrypoints/artist.schemas.js.map +1 -1
  156. package/dist/entrypoints/auth.d.ts +3 -3
  157. package/dist/entrypoints/auth.d.ts.map +1 -1
  158. package/dist/entrypoints/auth.js +2 -2
  159. package/dist/entrypoints/auth.js.map +1 -1
  160. package/dist/entrypoints/auth.schemas.d.ts +2 -1
  161. package/dist/entrypoints/auth.schemas.d.ts.map +1 -1
  162. package/dist/entrypoints/auth.schemas.js +1 -2
  163. package/dist/entrypoints/auth.schemas.js.map +1 -1
  164. package/dist/entrypoints/base.schemas.d.ts +2 -1
  165. package/dist/entrypoints/base.schemas.d.ts.map +1 -1
  166. package/dist/entrypoints/base.schemas.js +1 -2
  167. package/dist/entrypoints/base.schemas.js.map +1 -1
  168. package/dist/entrypoints/cache.d.ts +2 -0
  169. package/dist/entrypoints/cache.d.ts.map +1 -0
  170. package/dist/entrypoints/cache.js +2 -0
  171. package/dist/entrypoints/cache.js.map +1 -0
  172. package/dist/entrypoints/cache.schemas.d.ts +2 -0
  173. package/dist/entrypoints/cache.schemas.d.ts.map +1 -0
  174. package/dist/entrypoints/cache.schemas.js +2 -0
  175. package/dist/entrypoints/cache.schemas.js.map +1 -0
  176. package/dist/entrypoints/chart.d.ts +3 -3
  177. package/dist/entrypoints/chart.d.ts.map +1 -1
  178. package/dist/entrypoints/chart.js +2 -2
  179. package/dist/entrypoints/chart.js.map +1 -1
  180. package/dist/entrypoints/chart.schemas.d.ts +2 -1
  181. package/dist/entrypoints/chart.schemas.d.ts.map +1 -1
  182. package/dist/entrypoints/chart.schemas.js +1 -2
  183. package/dist/entrypoints/chart.schemas.js.map +1 -1
  184. package/dist/entrypoints/core.d.ts +5 -0
  185. package/dist/entrypoints/core.d.ts.map +1 -0
  186. package/dist/entrypoints/core.js +5 -0
  187. package/dist/entrypoints/core.js.map +1 -0
  188. package/dist/entrypoints/core.schemas.d.ts +3 -0
  189. package/dist/entrypoints/core.schemas.d.ts.map +1 -0
  190. package/dist/entrypoints/core.schemas.js +2 -0
  191. package/dist/entrypoints/core.schemas.js.map +1 -0
  192. package/dist/entrypoints/exporter.d.ts +3 -0
  193. package/dist/entrypoints/exporter.d.ts.map +1 -0
  194. package/dist/entrypoints/exporter.js +3 -0
  195. package/dist/entrypoints/exporter.js.map +1 -0
  196. package/dist/entrypoints/exporter.schemas.d.ts +3 -0
  197. package/dist/entrypoints/exporter.schemas.d.ts.map +1 -0
  198. package/dist/entrypoints/exporter.schemas.js +2 -0
  199. package/dist/entrypoints/exporter.schemas.js.map +1 -0
  200. package/dist/entrypoints/geo.d.ts +3 -3
  201. package/dist/entrypoints/geo.d.ts.map +1 -1
  202. package/dist/entrypoints/geo.js +2 -2
  203. package/dist/entrypoints/geo.js.map +1 -1
  204. package/dist/entrypoints/geo.schemas.d.ts +2 -1
  205. package/dist/entrypoints/geo.schemas.d.ts.map +1 -1
  206. package/dist/entrypoints/geo.schemas.js +1 -2
  207. package/dist/entrypoints/geo.schemas.js.map +1 -1
  208. package/dist/entrypoints/insights.d.ts +3 -3
  209. package/dist/entrypoints/insights.d.ts.map +1 -1
  210. package/dist/entrypoints/insights.js +2 -2
  211. package/dist/entrypoints/insights.js.map +1 -1
  212. package/dist/entrypoints/insights.schemas.d.ts +2 -1
  213. package/dist/entrypoints/insights.schemas.d.ts.map +1 -1
  214. package/dist/entrypoints/insights.schemas.js +1 -2
  215. package/dist/entrypoints/insights.schemas.js.map +1 -1
  216. package/dist/entrypoints/library.d.ts +3 -3
  217. package/dist/entrypoints/library.d.ts.map +1 -1
  218. package/dist/entrypoints/library.js +2 -2
  219. package/dist/entrypoints/library.js.map +1 -1
  220. package/dist/entrypoints/library.schemas.d.ts +2 -1
  221. package/dist/entrypoints/library.schemas.d.ts.map +1 -1
  222. package/dist/entrypoints/library.schemas.js +1 -2
  223. package/dist/entrypoints/library.schemas.js.map +1 -1
  224. package/dist/entrypoints/playlists.d.ts +3 -0
  225. package/dist/entrypoints/playlists.d.ts.map +1 -0
  226. package/dist/entrypoints/playlists.js +3 -0
  227. package/dist/entrypoints/playlists.js.map +1 -0
  228. package/dist/entrypoints/playlists.schemas.d.ts +3 -0
  229. package/dist/entrypoints/playlists.schemas.d.ts.map +1 -0
  230. package/dist/entrypoints/playlists.schemas.js +2 -0
  231. package/dist/entrypoints/playlists.schemas.js.map +1 -0
  232. package/dist/entrypoints/reports.d.ts +4 -0
  233. package/dist/entrypoints/reports.d.ts.map +1 -0
  234. package/dist/entrypoints/reports.js +3 -0
  235. package/dist/entrypoints/reports.js.map +1 -0
  236. package/dist/entrypoints/reports.schemas.d.ts +3 -0
  237. package/dist/entrypoints/reports.schemas.d.ts.map +1 -0
  238. package/dist/entrypoints/reports.schemas.js +2 -0
  239. package/dist/entrypoints/reports.schemas.js.map +1 -0
  240. package/dist/entrypoints/tag.d.ts +3 -3
  241. package/dist/entrypoints/tag.d.ts.map +1 -1
  242. package/dist/entrypoints/tag.js +2 -2
  243. package/dist/entrypoints/tag.js.map +1 -1
  244. package/dist/entrypoints/tag.schemas.d.ts +2 -1
  245. package/dist/entrypoints/tag.schemas.d.ts.map +1 -1
  246. package/dist/entrypoints/tag.schemas.js +1 -2
  247. package/dist/entrypoints/tag.schemas.js.map +1 -1
  248. package/dist/entrypoints/track.d.ts +3 -3
  249. package/dist/entrypoints/track.d.ts.map +1 -1
  250. package/dist/entrypoints/track.js +2 -2
  251. package/dist/entrypoints/track.js.map +1 -1
  252. package/dist/entrypoints/track.schemas.d.ts +2 -1
  253. package/dist/entrypoints/track.schemas.d.ts.map +1 -1
  254. package/dist/entrypoints/track.schemas.js +1 -2
  255. package/dist/entrypoints/track.schemas.js.map +1 -1
  256. package/dist/entrypoints/user.d.ts +3 -3
  257. package/dist/entrypoints/user.d.ts.map +1 -1
  258. package/dist/entrypoints/user.js +2 -2
  259. package/dist/entrypoints/user.js.map +1 -1
  260. package/dist/entrypoints/user.schemas.d.ts +2 -1
  261. package/dist/entrypoints/user.schemas.d.ts.map +1 -1
  262. package/dist/entrypoints/user.schemas.js +1 -2
  263. package/dist/entrypoints/user.schemas.js.map +1 -1
  264. package/dist/entrypoints/watcher.d.ts +2 -0
  265. package/dist/entrypoints/watcher.d.ts.map +1 -0
  266. package/dist/entrypoints/watcher.js +2 -0
  267. package/dist/entrypoints/watcher.js.map +1 -0
  268. package/dist/entrypoints/watcher.schemas.d.ts +2 -0
  269. package/dist/entrypoints/watcher.schemas.d.ts.map +1 -0
  270. package/dist/entrypoints/watcher.schemas.js +2 -0
  271. package/dist/entrypoints/watcher.schemas.js.map +1 -0
  272. package/dist/exporter/engines/library.d.ts +4 -0
  273. package/dist/exporter/engines/library.d.ts.map +1 -0
  274. package/dist/exporter/engines/library.js +34 -0
  275. package/dist/exporter/engines/library.js.map +1 -0
  276. package/dist/exporter/engines/loved.d.ts +4 -0
  277. package/dist/exporter/engines/loved.d.ts.map +1 -0
  278. package/dist/exporter/engines/loved.js +35 -0
  279. package/dist/exporter/engines/loved.js.map +1 -0
  280. package/dist/exporter/engines/scrobbles.d.ts +4 -0
  281. package/dist/exporter/engines/scrobbles.d.ts.map +1 -0
  282. package/dist/exporter/engines/scrobbles.js +74 -0
  283. package/dist/exporter/engines/scrobbles.js.map +1 -0
  284. package/dist/exporter/formats/csv.d.ts +5 -0
  285. package/dist/exporter/formats/csv.d.ts.map +1 -0
  286. package/dist/exporter/formats/csv.js +35 -0
  287. package/dist/exporter/formats/csv.js.map +1 -0
  288. package/dist/exporter/formats/jsonl.d.ts +2 -0
  289. package/dist/exporter/formats/jsonl.d.ts.map +1 -0
  290. package/dist/exporter/formats/jsonl.js +4 -0
  291. package/dist/exporter/formats/jsonl.js.map +1 -0
  292. package/dist/exporter/formats/listenbrainz.d.ts +3 -0
  293. package/dist/exporter/formats/listenbrainz.d.ts.map +1 -0
  294. package/dist/exporter/formats/listenbrainz.js +19 -0
  295. package/dist/exporter/formats/listenbrainz.js.map +1 -0
  296. package/dist/exporter/index.d.ts +6 -0
  297. package/dist/exporter/index.d.ts.map +1 -0
  298. package/dist/exporter/index.js +6 -0
  299. package/dist/exporter/index.js.map +1 -0
  300. package/dist/exporter/schemas.d.ts +291 -0
  301. package/dist/exporter/schemas.d.ts.map +1 -0
  302. package/dist/exporter/schemas.js +81 -0
  303. package/dist/exporter/schemas.js.map +1 -0
  304. package/dist/exporter/service.d.ts +30 -0
  305. package/dist/exporter/service.d.ts.map +1 -0
  306. package/dist/exporter/service.js +11 -0
  307. package/dist/exporter/service.js.map +1 -0
  308. package/dist/index.d.ts +18 -24
  309. package/dist/index.d.ts.map +1 -1
  310. package/dist/index.js +21 -16
  311. package/dist/index.js.map +1 -1
  312. package/dist/insights/algorithms/album-habits.d.ts +7 -0
  313. package/dist/insights/algorithms/album-habits.d.ts.map +1 -0
  314. package/dist/insights/algorithms/album-habits.js +154 -0
  315. package/dist/insights/algorithms/album-habits.js.map +1 -0
  316. package/dist/{services/insights → insights/algorithms}/binges.d.ts +1 -1
  317. package/dist/insights/algorithms/binges.d.ts.map +1 -0
  318. package/dist/{services/insights → insights/algorithms}/binges.js +2 -2
  319. package/dist/insights/algorithms/binges.js.map +1 -0
  320. package/dist/{services/insights → insights/algorithms}/compare.d.ts +1 -1
  321. package/dist/insights/algorithms/compare.d.ts.map +1 -0
  322. package/dist/{services/insights → insights/algorithms}/compare.js +3 -3
  323. package/dist/insights/algorithms/compare.js.map +1 -0
  324. package/dist/insights/algorithms/decay.d.ts +11 -0
  325. package/dist/insights/algorithms/decay.d.ts.map +1 -0
  326. package/dist/insights/algorithms/decay.js +154 -0
  327. package/dist/insights/algorithms/decay.js.map +1 -0
  328. package/dist/{services/insights → insights/algorithms}/discoveries.d.ts +1 -1
  329. package/dist/insights/algorithms/discoveries.d.ts.map +1 -0
  330. package/dist/{services/insights → insights/algorithms}/discoveries.js +2 -2
  331. package/dist/insights/algorithms/discoveries.js.map +1 -0
  332. package/dist/insights/algorithms/genres.d.ts +11 -0
  333. package/dist/insights/algorithms/genres.d.ts.map +1 -0
  334. package/dist/insights/algorithms/genres.js +201 -0
  335. package/dist/insights/algorithms/genres.js.map +1 -0
  336. package/dist/insights/algorithms/group.d.ts +8 -0
  337. package/dist/insights/algorithms/group.d.ts.map +1 -0
  338. package/dist/insights/algorithms/group.js +127 -0
  339. package/dist/insights/algorithms/group.js.map +1 -0
  340. package/dist/{services/insights → insights/algorithms}/hours.d.ts +1 -1
  341. package/dist/insights/algorithms/hours.d.ts.map +1 -0
  342. package/dist/{services/insights → insights/algorithms}/hours.js +2 -2
  343. package/dist/insights/algorithms/hours.js.map +1 -0
  344. package/dist/{services/insights → insights/algorithms}/mood.d.ts +1 -1
  345. package/dist/insights/algorithms/mood.d.ts.map +1 -0
  346. package/dist/{services/insights → insights/algorithms}/mood.js +4 -4
  347. package/dist/insights/algorithms/mood.js.map +1 -0
  348. package/dist/{services/insights → insights/algorithms}/now-playing.d.ts +1 -1
  349. package/dist/{services/insights → insights/algorithms}/now-playing.d.ts.map +1 -1
  350. package/dist/{services/insights → insights/algorithms}/now-playing.js +2 -2
  351. package/dist/insights/algorithms/now-playing.js.map +1 -0
  352. package/dist/insights/algorithms/obscurity.d.ts +27 -0
  353. package/dist/insights/algorithms/obscurity.d.ts.map +1 -0
  354. package/dist/insights/algorithms/obscurity.js +158 -0
  355. package/dist/insights/algorithms/obscurity.js.map +1 -0
  356. package/dist/{services/insights → insights/algorithms}/personality.d.ts +1 -1
  357. package/dist/insights/algorithms/personality.d.ts.map +1 -0
  358. package/dist/{services/insights → insights/algorithms}/personality.js +1 -1
  359. package/dist/insights/algorithms/personality.js.map +1 -0
  360. package/dist/insights/algorithms/recommendations.d.ts +11 -0
  361. package/dist/insights/algorithms/recommendations.d.ts.map +1 -0
  362. package/dist/insights/algorithms/recommendations.js +121 -0
  363. package/dist/insights/algorithms/recommendations.js.map +1 -0
  364. package/dist/insights/algorithms/streaks.d.ts +11 -0
  365. package/dist/insights/algorithms/streaks.d.ts.map +1 -0
  366. package/dist/insights/algorithms/streaks.js +178 -0
  367. package/dist/insights/algorithms/streaks.js.map +1 -0
  368. package/dist/{services/insights → insights/algorithms}/summary.d.ts +1 -1
  369. package/dist/insights/algorithms/summary.d.ts.map +1 -0
  370. package/dist/{services/insights → insights/algorithms}/summary.js +3 -3
  371. package/dist/insights/algorithms/summary.js.map +1 -0
  372. package/dist/{services/insights → insights/algorithms}/trends.d.ts +1 -1
  373. package/dist/insights/algorithms/trends.d.ts.map +1 -0
  374. package/dist/{services/insights → insights/algorithms}/trends.js +3 -3
  375. package/dist/insights/algorithms/trends.js.map +1 -0
  376. package/dist/insights/index.d.ts +3 -0
  377. package/dist/insights/index.d.ts.map +1 -0
  378. package/dist/insights/index.js +3 -0
  379. package/dist/insights/index.js.map +1 -0
  380. package/dist/insights/lib/binges.d.ts.map +1 -0
  381. package/dist/insights/lib/binges.js.map +1 -0
  382. package/dist/insights/lib/compare.d.ts.map +1 -0
  383. package/dist/insights/lib/compare.js.map +1 -0
  384. package/dist/insights/lib/discoveries.d.ts.map +1 -0
  385. package/dist/insights/lib/discoveries.js.map +1 -0
  386. package/dist/insights/lib/diversity.d.ts.map +1 -0
  387. package/dist/insights/lib/diversity.js.map +1 -0
  388. package/dist/insights/lib/hours.d.ts.map +1 -0
  389. package/dist/insights/lib/hours.js.map +1 -0
  390. package/dist/insights/lib/mood.d.ts.map +1 -0
  391. package/dist/insights/lib/mood.js.map +1 -0
  392. package/dist/{services/insights → insights}/lib/periods.d.ts +1 -1
  393. package/dist/insights/lib/periods.d.ts.map +1 -0
  394. package/dist/insights/lib/periods.js.map +1 -0
  395. package/dist/insights/lib/personality.d.ts.map +1 -0
  396. package/dist/insights/lib/personality.js.map +1 -0
  397. package/dist/insights/lib/trends.d.ts.map +1 -0
  398. package/dist/insights/lib/trends.js.map +1 -0
  399. package/dist/insights/schemas.d.ts +1415 -0
  400. package/dist/insights/schemas.d.ts.map +1 -0
  401. package/dist/{services/insights.schemas.js → insights/schemas.js} +291 -2
  402. package/dist/insights/schemas.js.map +1 -0
  403. package/dist/insights/service.d.ts +191 -0
  404. package/dist/insights/service.d.ts.map +1 -0
  405. package/dist/insights/service.js +44 -0
  406. package/dist/insights/service.js.map +1 -0
  407. package/dist/playlists/formatters/csv.d.ts +3 -0
  408. package/dist/playlists/formatters/csv.d.ts.map +1 -0
  409. package/dist/playlists/formatters/csv.js +18 -0
  410. package/dist/playlists/formatters/csv.js.map +1 -0
  411. package/dist/playlists/formatters/m3u.d.ts +3 -0
  412. package/dist/playlists/formatters/m3u.d.ts.map +1 -0
  413. package/dist/playlists/formatters/m3u.js +10 -0
  414. package/dist/playlists/formatters/m3u.js.map +1 -0
  415. package/dist/playlists/formatters/spotifymatch.d.ts +3 -0
  416. package/dist/playlists/formatters/spotifymatch.d.ts.map +1 -0
  417. package/dist/playlists/formatters/spotifymatch.js +4 -0
  418. package/dist/playlists/formatters/spotifymatch.js.map +1 -0
  419. package/dist/playlists/generators/generator.d.ts +4 -0
  420. package/dist/playlists/generators/generator.d.ts.map +1 -0
  421. package/dist/playlists/generators/generator.js +158 -0
  422. package/dist/playlists/generators/generator.js.map +1 -0
  423. package/dist/playlists/index.d.ts +6 -0
  424. package/dist/playlists/index.d.ts.map +1 -0
  425. package/dist/playlists/index.js +6 -0
  426. package/dist/playlists/index.js.map +1 -0
  427. package/dist/playlists/schemas.d.ts +150 -0
  428. package/dist/playlists/schemas.d.ts.map +1 -0
  429. package/dist/playlists/schemas.js +53 -0
  430. package/dist/playlists/schemas.js.map +1 -0
  431. package/dist/playlists/service.d.ts +28 -0
  432. package/dist/playlists/service.d.ts.map +1 -0
  433. package/dist/playlists/service.js +27 -0
  434. package/dist/playlists/service.js.map +1 -0
  435. package/dist/reports/generators/digest.d.ts +4 -0
  436. package/dist/reports/generators/digest.d.ts.map +1 -0
  437. package/dist/reports/generators/digest.js +95 -0
  438. package/dist/reports/generators/digest.js.map +1 -0
  439. package/dist/reports/generators/milestones.d.ts +4 -0
  440. package/dist/reports/generators/milestones.d.ts.map +1 -0
  441. package/dist/reports/generators/milestones.js +59 -0
  442. package/dist/reports/generators/milestones.js.map +1 -0
  443. package/dist/reports/generators/wrapped.d.ts +4 -0
  444. package/dist/reports/generators/wrapped.d.ts.map +1 -0
  445. package/dist/reports/generators/wrapped.js +179 -0
  446. package/dist/reports/generators/wrapped.js.map +1 -0
  447. package/dist/reports/index.d.ts +3 -0
  448. package/dist/reports/index.d.ts.map +1 -0
  449. package/dist/reports/index.js +3 -0
  450. package/dist/reports/index.js.map +1 -0
  451. package/dist/reports/schemas.d.ts +244 -0
  452. package/dist/reports/schemas.d.ts.map +1 -0
  453. package/dist/reports/schemas.js +92 -0
  454. package/dist/reports/schemas.js.map +1 -0
  455. package/dist/reports/service.d.ts +30 -0
  456. package/dist/reports/service.d.ts.map +1 -0
  457. package/dist/reports/service.js +11 -0
  458. package/dist/reports/service.js.map +1 -0
  459. package/dist/utils.d.ts +3 -2
  460. package/dist/utils.d.ts.map +1 -1
  461. package/dist/utils.js +19 -2
  462. package/dist/utils.js.map +1 -1
  463. package/dist/watcher/emitter.d.ts +14 -0
  464. package/dist/watcher/emitter.d.ts.map +1 -0
  465. package/dist/watcher/emitter.js +72 -0
  466. package/dist/watcher/emitter.js.map +1 -0
  467. package/dist/watcher/index.d.ts +5 -0
  468. package/dist/watcher/index.d.ts.map +1 -0
  469. package/dist/watcher/index.js +5 -0
  470. package/dist/watcher/index.js.map +1 -0
  471. package/dist/watcher/schemas.d.ts +39 -0
  472. package/dist/watcher/schemas.d.ts.map +1 -0
  473. package/dist/watcher/schemas.js +33 -0
  474. package/dist/watcher/schemas.js.map +1 -0
  475. package/dist/watcher/service.d.ts +15 -0
  476. package/dist/watcher/service.d.ts.map +1 -0
  477. package/dist/watcher/service.js +8 -0
  478. package/dist/watcher/service.js.map +1 -0
  479. package/dist/watcher/watcher.d.ts +35 -0
  480. package/dist/watcher/watcher.d.ts.map +1 -0
  481. package/dist/watcher/watcher.js +196 -0
  482. package/dist/watcher/watcher.js.map +1 -0
  483. package/package.json +49 -3
  484. package/dist/services/album.d.ts.map +0 -1
  485. package/dist/services/album.js.map +0 -1
  486. package/dist/services/album.schemas.d.ts.map +0 -1
  487. package/dist/services/album.schemas.js.map +0 -1
  488. package/dist/services/artist.d.ts.map +0 -1
  489. package/dist/services/artist.js.map +0 -1
  490. package/dist/services/artist.schemas.d.ts.map +0 -1
  491. package/dist/services/artist.schemas.js.map +0 -1
  492. package/dist/services/auth.d.ts.map +0 -1
  493. package/dist/services/auth.js.map +0 -1
  494. package/dist/services/auth.schemas.d.ts.map +0 -1
  495. package/dist/services/auth.schemas.js.map +0 -1
  496. package/dist/services/chart.d.ts.map +0 -1
  497. package/dist/services/chart.js +0 -9
  498. package/dist/services/chart.js.map +0 -1
  499. package/dist/services/chart.schemas.d.ts.map +0 -1
  500. package/dist/services/chart.schemas.js.map +0 -1
  501. package/dist/services/geo.d.ts.map +0 -1
  502. package/dist/services/geo.js +0 -8
  503. package/dist/services/geo.js.map +0 -1
  504. package/dist/services/geo.schemas.d.ts.map +0 -1
  505. package/dist/services/geo.schemas.js.map +0 -1
  506. package/dist/services/index.d.ts +0 -22
  507. package/dist/services/index.d.ts.map +0 -1
  508. package/dist/services/index.js +0 -23
  509. package/dist/services/index.js.map +0 -1
  510. package/dist/services/insights/binges.d.ts.map +0 -1
  511. package/dist/services/insights/binges.js.map +0 -1
  512. package/dist/services/insights/compare.d.ts.map +0 -1
  513. package/dist/services/insights/compare.js.map +0 -1
  514. package/dist/services/insights/discoveries.d.ts.map +0 -1
  515. package/dist/services/insights/discoveries.js.map +0 -1
  516. package/dist/services/insights/hours.d.ts.map +0 -1
  517. package/dist/services/insights/hours.js.map +0 -1
  518. package/dist/services/insights/lib/binges.d.ts.map +0 -1
  519. package/dist/services/insights/lib/binges.js.map +0 -1
  520. package/dist/services/insights/lib/compare.d.ts.map +0 -1
  521. package/dist/services/insights/lib/compare.js.map +0 -1
  522. package/dist/services/insights/lib/discoveries.d.ts.map +0 -1
  523. package/dist/services/insights/lib/discoveries.js.map +0 -1
  524. package/dist/services/insights/lib/diversity.d.ts.map +0 -1
  525. package/dist/services/insights/lib/diversity.js.map +0 -1
  526. package/dist/services/insights/lib/hours.d.ts.map +0 -1
  527. package/dist/services/insights/lib/hours.js.map +0 -1
  528. package/dist/services/insights/lib/mood.d.ts.map +0 -1
  529. package/dist/services/insights/lib/mood.js.map +0 -1
  530. package/dist/services/insights/lib/periods.d.ts.map +0 -1
  531. package/dist/services/insights/lib/periods.js.map +0 -1
  532. package/dist/services/insights/lib/personality.d.ts.map +0 -1
  533. package/dist/services/insights/lib/personality.js.map +0 -1
  534. package/dist/services/insights/lib/trends.d.ts.map +0 -1
  535. package/dist/services/insights/lib/trends.js.map +0 -1
  536. package/dist/services/insights/mood.d.ts.map +0 -1
  537. package/dist/services/insights/mood.js.map +0 -1
  538. package/dist/services/insights/now-playing.js.map +0 -1
  539. package/dist/services/insights/personality.d.ts.map +0 -1
  540. package/dist/services/insights/personality.js.map +0 -1
  541. package/dist/services/insights/summary.d.ts.map +0 -1
  542. package/dist/services/insights/summary.js.map +0 -1
  543. package/dist/services/insights/trends.d.ts.map +0 -1
  544. package/dist/services/insights/trends.js.map +0 -1
  545. package/dist/services/insights.d.ts +0 -96
  546. package/dist/services/insights.d.ts.map +0 -1
  547. package/dist/services/insights.js +0 -26
  548. package/dist/services/insights.js.map +0 -1
  549. package/dist/services/insights.schemas.d.ts +0 -710
  550. package/dist/services/insights.schemas.d.ts.map +0 -1
  551. package/dist/services/insights.schemas.js.map +0 -1
  552. package/dist/services/library.d.ts.map +0 -1
  553. package/dist/services/library.js +0 -7
  554. package/dist/services/library.js.map +0 -1
  555. package/dist/services/library.schemas.d.ts.map +0 -1
  556. package/dist/services/library.schemas.js.map +0 -1
  557. package/dist/services/schemas/base.entities.schemas.d.ts.map +0 -1
  558. package/dist/services/schemas/base.entities.schemas.js.map +0 -1
  559. package/dist/services/schemas/base.entity-names.schemas.d.ts.map +0 -1
  560. package/dist/services/schemas/base.entity-names.schemas.js.map +0 -1
  561. package/dist/services/schemas/base.metadata.schemas.d.ts.map +0 -1
  562. package/dist/services/schemas/base.metadata.schemas.js.map +0 -1
  563. package/dist/services/schemas/base.pagination.schemas.d.ts.map +0 -1
  564. package/dist/services/schemas/base.pagination.schemas.js.map +0 -1
  565. package/dist/services/schemas/base.primitives.schemas.d.ts.map +0 -1
  566. package/dist/services/schemas/base.primitives.schemas.js.map +0 -1
  567. package/dist/services/schemas/index.d.ts.map +0 -1
  568. package/dist/services/schemas/index.js.map +0 -1
  569. package/dist/services/tag.d.ts.map +0 -1
  570. package/dist/services/tag.js.map +0 -1
  571. package/dist/services/tag.schemas.d.ts.map +0 -1
  572. package/dist/services/tag.schemas.js.map +0 -1
  573. package/dist/services/track.d.ts.map +0 -1
  574. package/dist/services/track.js.map +0 -1
  575. package/dist/services/track.schemas.d.ts.map +0 -1
  576. package/dist/services/track.schemas.js.map +0 -1
  577. package/dist/services/track.utils.d.ts.map +0 -1
  578. package/dist/services/track.utils.js.map +0 -1
  579. package/dist/services/user.d.ts.map +0 -1
  580. package/dist/services/user.js +0 -19
  581. package/dist/services/user.js.map +0 -1
  582. package/dist/services/user.schemas.d.ts.map +0 -1
  583. package/dist/services/user.schemas.js.map +0 -1
  584. /package/dist/{services → core/schemas}/album.schemas.d.ts +0 -0
  585. /package/dist/{services → core/schemas}/artist.schemas.d.ts +0 -0
  586. /package/dist/{services → core/schemas}/auth.schemas.d.ts +0 -0
  587. /package/dist/{services → core/schemas}/auth.schemas.js +0 -0
  588. /package/dist/{services/schemas → core/schemas/base}/base.entities.schemas.d.ts +0 -0
  589. /package/dist/{services/schemas → core/schemas/base}/base.entities.schemas.js +0 -0
  590. /package/dist/{services/schemas → core/schemas/base}/base.entity-names.schemas.d.ts +0 -0
  591. /package/dist/{services/schemas → core/schemas/base}/base.entity-names.schemas.js +0 -0
  592. /package/dist/{services/schemas → core/schemas/base}/base.metadata.schemas.d.ts +0 -0
  593. /package/dist/{services/schemas → core/schemas/base}/base.metadata.schemas.js +0 -0
  594. /package/dist/{services/schemas → core/schemas/base}/base.pagination.schemas.d.ts +0 -0
  595. /package/dist/{services/schemas → core/schemas/base}/base.pagination.schemas.js +0 -0
  596. /package/dist/{services/schemas → core/schemas/base}/base.primitives.schemas.d.ts +0 -0
  597. /package/dist/{services/schemas → core/schemas/base}/base.primitives.schemas.js +0 -0
  598. /package/dist/{services/schemas → core/schemas/base}/index.d.ts +0 -0
  599. /package/dist/{services/schemas → core/schemas/base}/index.js +0 -0
  600. /package/dist/{services → core/schemas}/chart.schemas.d.ts +0 -0
  601. /package/dist/{services → core/schemas}/geo.schemas.d.ts +0 -0
  602. /package/dist/{services → core/schemas}/library.schemas.d.ts +0 -0
  603. /package/dist/{services → core/schemas}/tag.schemas.d.ts +0 -0
  604. /package/dist/{services → core/schemas}/track.schemas.d.ts +0 -0
  605. /package/dist/{services → core/schemas}/user.schemas.d.ts +0 -0
  606. /package/dist/{services → core/services}/track.utils.js +0 -0
  607. /package/dist/{services/insights → insights}/lib/binges.d.ts +0 -0
  608. /package/dist/{services/insights → insights}/lib/binges.js +0 -0
  609. /package/dist/{services/insights → insights}/lib/compare.d.ts +0 -0
  610. /package/dist/{services/insights → insights}/lib/compare.js +0 -0
  611. /package/dist/{services/insights → insights}/lib/discoveries.d.ts +0 -0
  612. /package/dist/{services/insights → insights}/lib/discoveries.js +0 -0
  613. /package/dist/{services/insights → insights}/lib/diversity.d.ts +0 -0
  614. /package/dist/{services/insights → insights}/lib/diversity.js +0 -0
  615. /package/dist/{services/insights → insights}/lib/hours.d.ts +0 -0
  616. /package/dist/{services/insights → insights}/lib/hours.js +0 -0
  617. /package/dist/{services/insights → insights}/lib/mood.d.ts +0 -0
  618. /package/dist/{services/insights → insights}/lib/mood.js +0 -0
  619. /package/dist/{services/insights → insights}/lib/periods.js +0 -0
  620. /package/dist/{services/insights → insights}/lib/personality.d.ts +0 -0
  621. /package/dist/{services/insights → insights}/lib/personality.js +0 -0
  622. /package/dist/{services/insights → insights}/lib/trends.d.ts +0 -0
  623. /package/dist/{services/insights → insights}/lib/trends.js +0 -0
package/CHANGELOG.md CHANGED
@@ -9,6 +9,71 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
9
9
  > [ansango/lastfm-api](https://github.com/ansango/lastfm-api). Entries below preserve the
10
10
  > historical package and repository names used by their original releases.
11
11
 
12
+ ## [3.6.0] - 2026-08-29
13
+
14
+ ### ✨ Features
15
+
16
+ - **watcher**: implement real-time scrobble watcher and event emitter (closes #164, #165) (#167) ([a9545a1](https://github.com/ansango/lastfm-api/commit/a9545a1))
17
+ - **cache**: implement pluggable cache layer (closes #163) (#166) ([4eaa1e0](https://github.com/ansango/lastfm-api/commit/4eaa1e0))
18
+
19
+ ### ♻️ Code Refactoring
20
+
21
+ - **index**: remove dotenv loading for environment variables ([57236a6](https://github.com/ansango/lastfm-api/commit/57236a6))
22
+
23
+ ### 🔧 Chores
24
+
25
+ - **docs**: update README with complete v3.5.0 features and remove dotenv and test-real ([e2abeb9](https://github.com/ansango/lastfm-api/commit/e2abeb9))
26
+
27
+
28
+ ## [3.5.0] - 2026-08-29
29
+
30
+ ### ✨ Features
31
+
32
+ - **exporter**: implement exporter namespace (closes #157) (#161) ([d7385ff](https://github.com/ansango/lastfm-api/commit/d7385ff))
33
+ - **playlists**: implement playlists namespace (closes #156) (#160) ([9113b17](https://github.com/ansango/lastfm-api/commit/9113b17))
34
+ - **reports**: implement reports namespace (closes #155) (#159) ([b5524e1](https://github.com/ansango/lastfm-api/commit/b5524e1))
35
+ - **core**: implement automatic async pagination and streaming iterators (closes #154) (#158) ([406caa0](https://github.com/ansango/lastfm-api/commit/406caa0))
36
+ - **insights**: implement compareTasteGroup (closes #143) (#150) ([49b69b4](https://github.com/ansango/lastfm-api/commit/49b69b4))
37
+ - **insights**: implement getSmartRecommendations and getBridgeArtists (closes #142) (#149) ([3b2b2f2](https://github.com/ansango/lastfm-api/commit/3b2b2f2))
38
+ - **insights**: implement getGenreBreakdown and getGenreEvolution (closes #141) (#148) ([4c82e23](https://github.com/ansango/lastfm-api/commit/4c82e23))
39
+ - **insights**: implement getAlbumHabits (closes #140) (#147) ([0b9ceeb](https://github.com/ansango/lastfm-api/commit/0b9ceeb))
40
+ - **insights**: implement getListeningStreaks and getListeningHeatmap (closes #139) (#146) ([756b4de](https://github.com/ansango/lastfm-api/commit/756b4de))
41
+ - **insights**: implement getForgottenFavorites and getObsessions (closes #138) (#145) ([aac4776](https://github.com/ansango/lastfm-api/commit/aac4776))
42
+ - **insights**: implement getObscurityScore (closes #137) (#144) ([83be889](https://github.com/ansango/lastfm-api/commit/83be889))
43
+
44
+ ### 🐛 Bug Fixes
45
+
46
+ - **ci**: point test-real to src and smoke-test core entrypoints ([847da33](https://github.com/ansango/lastfm-api/commit/847da33))
47
+
48
+ ### ♻️ Code Refactoring
49
+
50
+ - **arch**: decouple core canonical API from insights engine (closes #151) (#152) ([6e3b261](https://github.com/ansango/lastfm-api/commit/6e3b261))
51
+
52
+ ### 📚 Documentation
53
+
54
+ - **insights**: document 11 new analytical methods in README and api-coverage (closes #136) ([35f5d60](https://github.com/ansango/lastfm-api/commit/35f5d60))
55
+
56
+ ### 🔧 Chores
57
+
58
+ - **release**: bump version to v3.5.0 ([abcc3c7](https://github.com/ansango/lastfm-api/commit/abcc3c7))
59
+
60
+
61
+ ## [3.5.0] - 2026-08-29
62
+
63
+ ### ✨ Features
64
+
65
+ - **watcher**: implement real-time scrobble watcher and event emitter (closes #164, #165) (#167) ([a9545a1](https://github.com/ansango/lastfm-api/commit/a9545a1))
66
+ - **cache**: implement pluggable cache layer (closes #163) (#166) ([4eaa1e0](https://github.com/ansango/lastfm-api/commit/4eaa1e0))
67
+
68
+ ### ♻️ Code Refactoring
69
+
70
+ - **index**: remove dotenv loading for environment variables ([57236a6](https://github.com/ansango/lastfm-api/commit/57236a6))
71
+
72
+ ### 🔧 Chores
73
+
74
+ - **docs**: update README with complete v3.5.0 features and remove dotenv and test-real ([e2abeb9](https://github.com/ansango/lastfm-api/commit/e2abeb9))
75
+
76
+
12
77
  ## [3.4.0] - 2026-08-28
13
78
 
14
79
  ### ✨ Features
package/README.md CHANGED
@@ -15,7 +15,13 @@ A universal Last.fm API client for Node.js and Browser, written in TypeScript.
15
15
 
16
16
  - ✅ **Universal**: Works in Node.js (≥20.0.0) and Browser
17
17
  - ✅ **Complete coverage**: All 56 canonical Last.fm API methods across 9 namespaces
18
- - ✅ **Insights & Analytics Engine**: 9 high-level derived analytical views (Shannon diversity, enriched Now Playing, diurnal histograms, binge runs, ranking diffs, new discoveries, 2D mood classification, personality archetypes, and Jaccard user comparison)
18
+ - ✅ **Insights & Analytics Engine**: 20 high-level derived analytical views (Shannon diversity, enriched Now Playing, diurnal histograms, binge runs, ranking diffs, new discoveries, 2D mood classification, personality archetypes, obscurity scores, streaks, heatmaps, album habits, genre breakdown & evolution, smart recommendations, bridge artists, and user/group comparison)
19
+ - ✅ **Pluggable Cache Layer**: Zero-dependency caching for GET/read requests with `MemoryCacheStore` (LRU) and `StorageCacheStore` (localStorage), plus granular TTL by namespace/method
20
+ - ✅ **Real-Time Scrobble Watcher**: Isomorphic event-driven listening monitor emitting `nowPlaying`, `nowPlayingEnd`, `scrobble`, and `idle` events
21
+ - ✅ **Reports & Wrapped Engine**: Custom Year-in-Review, historical milestone projections, and monthly digests
22
+ - ✅ **Smart Playlists Generator**: Algorithmic playlist generation (heavy rotation, time capsule, deep cuts, discovery radar) with M3U and CSV exports
23
+ - ✅ **Bulk Data Exporter & Backup**: Resilient scrobble, loved tracks, and library catalog backup with UTS checkpointing and ListenBrainz/JSONL/CSV formats
24
+ - ✅ **Async Pagination & Streaming**: Native `for await` streaming iterators (`iterateItems`, `collectAll`, `iteratePages`) with automatic rate limiting and boundary controls
19
25
  - ✅ **TypeScript**: Full type safety with comprehensive type definitions
20
26
  - ✅ **Zod Schemas**: Runtime validation schemas for all types
21
27
  - ✅ **ESM**: Modern ES modules with tree-shaking support
@@ -31,6 +37,14 @@ A universal Last.fm API client for Node.js and Browser, written in TypeScript.
31
37
  - [Using the Client Class](#using-the-client-class)
32
38
  - [Using Global Configuration](#using-global-configuration)
33
39
  - [Using Individual Services](#using-individual-services)
40
+ - [Zod Schema Validation](#zod-schema-validation)
41
+ - [Pluggable Cache Layer](#pluggable-cache-layer)
42
+ - [Real-Time Scrobble Watcher](#real-time-scrobble-watcher)
43
+ - [Insights & Analytics Engine](#insights--analytics-engine)
44
+ - [Reports & Wrapped Engine](#reports--wrapped-engine)
45
+ - [Smart Playlists Generator](#smart-playlists-generator)
46
+ - [Bulk Data Exporter & Backup](#bulk-data-exporter--backup)
47
+ - [Async Pagination & Streaming Iterators](#async-pagination--streaming-iterators)
34
48
  - [Environment Variables](#environment-variables)
35
49
  - [Authentication & Scrobbling](#authentication--scrobbling)
36
50
  - [Error Handling](#error-handling)
@@ -213,6 +227,7 @@ const tracks = await trackService.search({ track: 'Come Together' });
213
227
  ```
214
228
 
215
229
  **Available service imports:**
230
+ - `@ansango/lastfm-api/core` (canonical methods + pagination)
216
231
  - `@ansango/lastfm-api/user`
217
232
  - `@ansango/lastfm-api/album`
218
233
  - `@ansango/lastfm-api/artist`
@@ -222,7 +237,12 @@ const tracks = await trackService.search({ track: 'Come Together' });
222
237
  - `@ansango/lastfm-api/geo`
223
238
  - `@ansango/lastfm-api/library`
224
239
  - `@ansango/lastfm-api/auth`
240
+ - `@ansango/lastfm-api/cache`
241
+ - `@ansango/lastfm-api/watcher`
225
242
  - `@ansango/lastfm-api/insights`
243
+ - `@ansango/lastfm-api/reports`
244
+ - `@ansango/lastfm-api/playlists`
245
+ - `@ansango/lastfm-api/exporter`
226
246
 
227
247
  ## Zod Schema Validation
228
248
 
@@ -236,6 +256,12 @@ Schemas are available through modular imports, following the same pattern as the
236
256
  import { userGetInfoRequestSchema, userGetInfoResponseSchema } from '@ansango/lastfm-api/user/schemas';
237
257
  import { albumSearchRequestSchema } from '@ansango/lastfm-api/album/schemas';
238
258
  import { trackGetInfoResponseSchema } from '@ansango/lastfm-api/track/schemas';
259
+ import { cacheOptionsSchema } from '@ansango/lastfm-api/cache/schemas';
260
+ import { watcherOptionsSchema } from '@ansango/lastfm-api/watcher/schemas';
261
+ import { insightsSummaryResponseSchema } from '@ansango/lastfm-api/insights/schemas';
262
+ import { reportsWrappedResponseSchema } from '@ansango/lastfm-api/reports/schemas';
263
+ import { playlistsGenerateResponseSchema } from '@ansango/lastfm-api/playlists/schemas';
264
+ import { exporterScrobblesResponseSchema } from '@ansango/lastfm-api/exporter/schemas';
239
265
  ```
240
266
 
241
267
  ### Usage Example
@@ -262,6 +288,7 @@ if (result.success) {
262
288
  ```
263
289
 
264
290
  **Available schema imports:**
291
+ - `@ansango/lastfm-api/core/schemas`
265
292
  - `@ansango/lastfm-api/user/schemas`
266
293
  - `@ansango/lastfm-api/album/schemas`
267
294
  - `@ansango/lastfm-api/artist/schemas`
@@ -271,12 +298,88 @@ if (result.success) {
271
298
  - `@ansango/lastfm-api/geo/schemas`
272
299
  - `@ansango/lastfm-api/library/schemas`
273
300
  - `@ansango/lastfm-api/auth/schemas`
301
+ - `@ansango/lastfm-api/cache/schemas`
302
+ - `@ansango/lastfm-api/watcher/schemas`
274
303
  - `@ansango/lastfm-api/insights/schemas`
304
+ - `@ansango/lastfm-api/reports/schemas`
305
+ - `@ansango/lastfm-api/playlists/schemas`
306
+ - `@ansango/lastfm-api/exporter/schemas`
275
307
  - `@ansango/lastfm-api/schemas` (base types like `imageSchema`, `datePropSchema`, etc.)
276
308
 
309
+ ## Pluggable Cache Layer
310
+
311
+ Transparent caching for read (`GET`) operations with configurable TTLs, LRU eviction, and interchangeable storage backends:
312
+
313
+ ```typescript
314
+ import { LastFmClient, MemoryCacheStore, StorageCacheStore } from '@ansango/lastfm-api';
315
+
316
+ // 1. Enable in-memory cache with granular TTL policies
317
+ const client = new LastFmClient({
318
+ apiKey: 'YOUR_API_KEY',
319
+ cache: {
320
+ defaultTtlMs: 300_000, // 5 minutes default
321
+ ttlByNamespace: {
322
+ artist: 86_400_000, // 24 hours for artist metadata
323
+ user: 60_000, // 1 minute for user endpoints
324
+ },
325
+ ttlByMethod: {
326
+ 'user.getRecentTracks': 15_000, // 15 seconds for recent tracks
327
+ },
328
+ },
329
+ });
330
+
331
+ // 2. First call performs network fetch; second call hits cache instantly
332
+ const artist1 = await client.artist.getInfo({ artist: 'Radiohead' });
333
+ const artist2 = await client.artist.getInfo({ artist: 'Radiohead' }); // Cache hit!
334
+
335
+ // 3. Inspect or manage cache metrics directly
336
+ console.log(client.cache.stats()); // { hits: 1, misses: 1, size: 1 }
337
+ await client.cache.clear();
338
+ ```
339
+
340
+ ## Real-Time Scrobble Watcher
341
+
342
+ Isomorphic event-driven listening monitor emitting events as playback updates in real time:
343
+
344
+ ```typescript
345
+ import { LastFmClient } from '@ansango/lastfm-api';
346
+
347
+ const client = new LastFmClient({ apiKey: 'YOUR_API_KEY' });
348
+
349
+ // Create a watcher for a user with 10-second polling
350
+ const watcher = client.watcher.watchUser({
351
+ user: 'ansango',
352
+ intervalMs: 10_000,
353
+ idleThresholdMs: 300_000, // 5 minutes without activity triggers idle
354
+ });
355
+
356
+ // Event listeners
357
+ watcher.on('nowPlaying', (track) => {
358
+ console.log(`🎵 Now Playing: ${track.name} by ${track.artist}`);
359
+ });
360
+
361
+ watcher.on('nowPlayingEnd', (track) => {
362
+ console.log(`⏹️ Finished: ${track.name}`);
363
+ });
364
+
365
+ watcher.on('scrobble', (track) => {
366
+ console.log(`✅ Scrobble recorded: ${track.name} (UTS: ${track.uts})`);
367
+ });
368
+
369
+ watcher.on('idle', ({ idleMinutes }) => {
370
+ console.log(`💤 User has been idle for ${idleMinutes} minutes`);
371
+ });
372
+
373
+ // Start polling
374
+ watcher.start();
375
+
376
+ // Stop when done
377
+ // watcher.stop();
378
+ ```
379
+
277
380
  ## Insights & Analytics Engine
278
381
 
279
- The package includes a built-in analytics engine providing 9 high-level derived views computed over Last.fm data:
382
+ The package includes a comprehensive, built-in analytics engine providing 20 high-level derived views and statistical metrics computed over Last.fm data:
280
383
 
281
384
  ```typescript
282
385
  import { createClient } from '@ansango/lastfm-api';
@@ -319,6 +422,133 @@ console.log(`Archetype: ${personality.archetype.emoji} ${personality.archetype.n
319
422
  // 9. User-to-User Taste Clash (Jaccard Similarity)
320
423
  const comparison = await client.insights.compareUsers({ userA: 'ansango', userB: 'friend' });
321
424
  console.log(`Taste Compatibility: ${comparison.compatibilityScore}% (Jaccard: ${comparison.jaccard})`);
425
+
426
+ // 10. Obscurity & Hipster Score (Hidden Gems & Mainstream Anchors)
427
+ const obscurity = await client.insights.getObscurityScore({ user: 'ansango', limit: 20 });
428
+ console.log(`Score: ${obscurity.obscurityScore}/100 (${obscurity.category})`);
429
+
430
+ // 11. Forgotten Favorites (Revival Candidates)
431
+ const forgotten = await client.insights.getForgottenFavorites({ user: 'ansango', historicPeriod: '12month', recentPeriod: '1month' });
432
+
433
+ // 12. Listening Obsession Episodes
434
+ const obsessions = await client.insights.getObsessions({ user: 'ansango', windowSize: 20, thresholdRatio: 0.35 });
435
+
436
+ // 13. Consecutive Daily Streaks & Dry Spells
437
+ const streaks = await client.insights.getListeningStreaks({ user: 'ansango' });
438
+ console.log(`Longest Streak: ${streaks.longestStreakDays} days`);
439
+
440
+ // 14. 365-Day Daily Heatmap
441
+ const heatmap = await client.insights.getListeningHeatmap({ user: 'ansango', days: 90 });
442
+
443
+ // 15. Album Habits & Cohesion Score (Album Purist vs Playlist Shuffler)
444
+ const habits = await client.insights.getAlbumHabits({ user: 'ansango', minSessionTracks: 3 });
445
+ console.log(`Cohesion: ${habits.cohesionScore}% (${habits.profile})`);
446
+
447
+ // 16. Genre Breakdown with HHI Concentration Index
448
+ const genres = await client.insights.getGenreBreakdown({ user: 'ansango', period: 'overall' });
449
+ console.log(`Specialization: ${genres.specializationLevel} (HHI: ${genres.hhiIndex})`);
450
+
451
+ // 17. Genre Evolution & Temporal Shifts (Rising, Fading, New)
452
+ const evolution = await client.insights.getGenreEvolution({ user: 'ansango', currentPeriod: '1month', previousPeriod: '12month' });
453
+
454
+ // 18. Smart Similarity Graph Recommendations
455
+ const recs = await client.insights.getSmartRecommendations({ user: 'ansango', seedLimit: 5, limit: 10 });
456
+
457
+ // 19. Bridge Artists Connecting Two Disparate Genres
458
+ const bridges = await client.insights.getBridgeArtists({ tagA: 'post-punk', tagB: 'electronic' });
459
+
460
+ // 20. Multi-User Taste Group Comparison (Consensus & Outlier Detection)
461
+ const group = await client.insights.compareTasteGroup({ users: ['alice', 'bob', 'carol'], period: 'overall' });
462
+ console.log(`Group Average Compatibility: ${group.groupAverageCompatibility}%`);
463
+ ```
464
+
465
+ ## Reports & Wrapped Engine
466
+
467
+ Generate shareable annual recaps, historical milestones, and monthly digests:
468
+
469
+ ```typescript
470
+ import { createClient } from '@ansango/lastfm-api';
471
+
472
+ const client = createClient();
473
+
474
+ // 1. Year in Review / Wrapped
475
+ const wrapped = await client.reports.getWrapped({ user: 'ansango', year: 2024 });
476
+ console.log(`Top Artist of the Year: ${wrapped.topArtists[0].name}`);
477
+ console.log(`Summer Anthem: ${wrapped.seasons.summer.topTrack} by ${wrapped.seasons.summer.topArtist}`);
478
+ console.log(`Busiest Day: ${wrapped.busiestDay.date} (${wrapped.busiestDay.scrobbles} plays)`);
479
+
480
+ // 2. Scrobble Milestones Tracker & Projection
481
+ const milestones = await client.reports.getMilestones({ user: 'ansango', targets: [1000, 5000, 10000, 50000] });
482
+ console.log(`Next milestone: ${milestones.nextMilestone.target} scrobbles (ETA: ${milestones.nextMilestone.projectedDate})`);
483
+
484
+ // 3. Monthly Comparative Digest
485
+ const digest = await client.reports.getMonthlyDigest({ user: 'ansango', year: 2024, month: 2 });
486
+ console.log(`Growth vs previous month: ${digest.growthPercentage}%`);
487
+ ```
488
+
489
+ ## Smart Playlists Generator
490
+
491
+ Algorithmic playlist creation with direct export to standard formats:
492
+
493
+ ```typescript
494
+ import { createClient } from '@ansango/lastfm-api';
495
+
496
+ const client = createClient();
497
+
498
+ // Generate smart playlist (time-capsule, deep-cuts, heavy-rotation, discovery-radar)
499
+ const playlist = await client.playlists.generate({
500
+ user: 'ansango',
501
+ mode: 'time-capsule',
502
+ limit: 25,
503
+ });
504
+
505
+ // Pre-rendered standard formats:
506
+ console.log(playlist.formats.m3u); // Standard #EXTM3U playlist file content
507
+ console.log(playlist.formats.csv); // CSV spreadsheet
508
+ console.log(playlist.formats.spotifyQueries); // Spotify search query list
509
+ ```
510
+
511
+ ## Bulk Data Exporter & Backup
512
+
513
+ Resilient scrobble history export with checkpointing and multiple output formats:
514
+
515
+ ```typescript
516
+ import { createClient } from '@ansango/lastfm-api';
517
+
518
+ const client = createClient();
519
+
520
+ // Export scrobbles with ListenBrainz / JSONL / CSV formatting & checkpointing
521
+ const exportData = await client.exporter.exportScrobbles({
522
+ user: 'ansango',
523
+ format: 'listenbrainz', // 'json' | 'jsonl' | 'csv' | 'listenbrainz'
524
+ limit: 1000,
525
+ });
526
+
527
+ // Resumable checkpoint timestamp
528
+ console.log(`Resume from: ${exportData.nextCheckpointUts}`);
529
+ ```
530
+
531
+ ## Async Pagination & Streaming Iterators
532
+
533
+ Stream large Last.fm datasets seamlessly using standard `for await` loops:
534
+
535
+ ```typescript
536
+ import { createClient, iterateItems } from '@ansango/lastfm-api';
537
+
538
+ const client = createClient();
539
+
540
+ for await (const track of iterateItems(
541
+ (params) => client.user.getRecentTracks(params),
542
+ (res) => ({
543
+ items: res.recenttracks?.track ?? [],
544
+ totalPages: Number(res.recenttracks?.['@attr']?.totalPages ?? 1),
545
+ currentPage: Number(res.recenttracks?.['@attr']?.page ?? 1),
546
+ }),
547
+ { user: 'ansango', limit: 200 },
548
+ { maxItems: 1000 }
549
+ )) {
550
+ console.log(`${track.name} - ${track.artist['#text']}`);
551
+ }
322
552
  ```
323
553
 
324
554
  ## Environment Variables
@@ -409,7 +639,7 @@ Before the browser flow works end-to-end, set a callback URL on your API account
409
639
 
410
640
  If you skip this step, the redirect after **Allow access** lands on a Last.fm error page instead of your URL, and the token is lost. You have to call `auth.getToken` again and re-authorize.
411
641
 
412
- > **Note:** `auth.getMobileSession` was removed in v4.0.0. Last.fm restricts that endpoint to mobile-classified API keys, which are not exposed through the public self-service create form; the browser flow above works for every API key Last.fm issues today.
642
+ > **Note:** `auth.getMobileSession` was removed in v3.3.0. Last.fm restricts that endpoint to mobile-classified API keys, which are not exposed through the public self-service create form; the browser flow above works for every API key Last.fm issues today.
413
643
 
414
644
  ### Passing the session key to write methods
415
645
 
@@ -473,6 +703,7 @@ The main client class with all services:
473
703
 
474
704
  ```typescript
475
705
  class LastFmClient {
706
+ core: LastFmCoreClient;
476
707
  user: UserService;
477
708
  album: AlbumService;
478
709
  artist: ArtistService;
@@ -483,6 +714,11 @@ class LastFmClient {
483
714
  library: LibraryService;
484
715
  auth: AuthService;
485
716
  insights: InsightsService;
717
+ reports: ReportsService;
718
+ playlists: PlaylistsService;
719
+ exporter: ExporterService;
720
+ cache: CacheService;
721
+ watcher: WatcherService;
486
722
 
487
723
  constructor(config?: Partial<LastFmConfig>);
488
724
  getConfig(): Readonly<LastFmConfig>;
@@ -508,8 +744,9 @@ function resetGlobalConfig(): void;
508
744
 
509
745
  ### Services
510
746
 
511
- The package covers all 56 canonical Last.fm API methods across 9 namespaces, plus 9 derived analytical methods in the `InsightsService`. See [docs/api-coverage.md](docs/api-coverage.md) for the full table.
747
+ The package covers all 56 canonical Last.fm API methods across 9 namespaces, plus 20 derived analytical methods in `InsightsService`, 3 reporting methods in `ReportsService`, 3 smart playlist methods in `PlaylistsService`, and 3 data export engines in `ExporterService` (83 total endpoints). See [docs/api-coverage.md](docs/api-coverage.md) for the full table.
512
748
 
749
+ - **CoreClient (`core`)**: Bundle of all 56 canonical Last.fm methods with built-in async pagination (`iterateItems`, `collectAll`, `iteratePages`)
513
750
  - **UserService**: 13 methods — `getInfo`, `getFriends`, `getLovedTracks`, `getRecentTracks`, `getTopAlbums`, `getTopArtists`, `getTopTags`, `getTopTracks`, `getWeeklyAlbumChart`, `getWeeklyArtistChart`, `getWeeklyChartList`, `getWeeklyTrackChart`, `getPersonalTags`
514
751
  - **AlbumService**: 6 methods — `getInfo`, `getTags`, `getTopTags`, `search`, `addTags`¹, `removeTag`¹
515
752
  - **ArtistService**: 10 methods — `getInfo`, `getTags`, `getSimilar`, `getTopTags`, `getTopAlbums`, `getTopTracks`, `search`, `getCorrection`, `addTags`¹, `removeTag`¹
@@ -518,8 +755,11 @@ The package covers all 56 canonical Last.fm API methods across 9 namespaces, plu
518
755
  - **ChartService**: 3 methods — `getTopArtists`, `getTopTags`, `getTopTracks`
519
756
  - **GeoService**: 2 methods — `getTopArtists`, `getTopTracks`
520
757
  - **LibraryService**: 1 method — `getArtists`
521
- - **AuthService**: 2 methods — `getSession`, `getToken` (removed `getMobileSession` in v4.0.0)
522
- - **InsightsService**: 9 methods — `getSummary`, `getNowPlaying`, `getHoursHistogram`, `getBinges`, `getTrends`, `getDiscoveries`, `getMood`, `getPersonality`, `compareUsers`
758
+ - **AuthService**: 2 methods — `getSession`, `getToken` (removed `getMobileSession` in v3.3.0)
759
+ - **InsightsService**: 20 methods — `getSummary`, `getNowPlaying`, `getHoursHistogram`, `getBinges`, `getTrends`, `getDiscoveries`, `getMood`, `getPersonality`, `compareUsers`, `getObscurityScore`, `getObsessions`, `getForgottenFavorites`, `getListeningStreaks`, `getListeningHeatmap`, `getAlbumHabits`, `getGenreBreakdown`, `getGenreEvolution`, `getSmartRecommendations`, `getBridgeArtists`, `compareTasteGroup`
760
+ - **ReportsService**: 3 methods — `getWrapped`, `getMilestones`, `getMonthlyDigest`
761
+ - **PlaylistsService**: 3 methods — `generate`, `exportM3U`, `exportCsv`
762
+ - **ExporterService**: 3 methods — `exportScrobbles`, `exportLovedTracks`, `exportLibrary`
523
763
 
524
764
  ¹ Requires an authenticated session.
525
765
 
@@ -574,10 +814,7 @@ bun run build
574
814
  bun run typecheck
575
815
 
576
816
  # Run deterministic unit tests (no network, mocked fetch)
577
- bun run test:unit
578
-
579
- # Run live integration (requires Last.fm credentials in .env)
580
- bun run test:integration:live
817
+ bun run test:unit # or simply 'bun test'
581
818
 
582
819
  # Lint (Biome — formatter + linter, single command)
583
820
  bun run lint
@@ -599,10 +836,10 @@ bun run clean
599
836
  ## Interactive API Explorer
600
837
 
601
838
  The repo ships with a local Hono + Scalar server under `tool/api-scalar/`
602
- that turns the package into a fully interactive OpenAPI explorer. All 57
603
- canonical Last.fm methods are wired declaratively from the package's own
604
- Zod schemas and service functions no method is hand-written, no schema
605
- is duplicated.
839
+ that turns the package into a fully interactive OpenAPI explorer. All 56
840
+ canonical Last.fm methods and 27 extension methods (83 total operations)
841
+ are wired declaratively into 5 collapsible sections from the package's
842
+ own Zod schemas and service functions.
606
843
 
607
844
  ```sh
608
845
  bun install --cwd tool/api-scalar
@@ -618,14 +855,10 @@ for the design notes.
618
855
 
619
856
  ### Testing
620
857
 
621
- The test suite is split into two layers:
622
-
623
- - **`bun run test:unit`** — deterministic tests with mocked `globalThis.fetch`. They cover every canonical Last.fm method that the package implements, assert the correct `namespace.method` routing, validate that `api_key`/`format=json` are present, and verify that Last.fm error envelopes surface as `LastFmApiError`. They do not require an API key or any network access, and they run as part of CI on every push and pull request.
624
- - **`bun run test:integration:live`** — runs `test-real.ts` against the real Last.fm API. It is **not** part of CI and must be invoked manually by a developer with valid credentials in `.env`.
625
-
626
- The `bun test` alias points to the deterministic suite, so a normal `bun test` is safe to run anywhere.
858
+ The test suite consists of deterministic unit tests with mocked `globalThis.fetch`:
627
859
 
628
- An `inventory.test.ts` file asserts the **57/57 canonical-method baseline** every namespace.method pair listed in the official Last.fm API index is exposed on the `LastFmClient` and callable. The per-namespace breakdown is mirrored in [docs/api-coverage.md](docs/api-coverage.md) and stays in sync with the inventory test.
860
+ - **`bun test`** (or **`bun run test:unit`**) — covers every method that the package implements, asserts the correct `namespace.method` routing, validates that `api_key`/`format=json` are present, and verifies that Last.fm error envelopes surface as `LastFmApiError`. They do not require an API key or any network access, and they run as part of CI on every push and pull request.
861
+ - **`inventory.test.ts`** — asserts the **56/56 canonical-method baseline** ensuring every namespace.method pair listed in the official Last.fm API index is exposed on the `LastFmClient` and callable. The per-namespace breakdown is mirrored in [docs/api-coverage.md](docs/api-coverage.md).
629
862
 
630
863
  ### Release Process
631
864
 
@@ -0,0 +1,7 @@
1
+ export * from './interface.js';
2
+ export * from './manager.js';
3
+ export * from './schemas.js';
4
+ export * from './service.js';
5
+ export * from './stores/memory.js';
6
+ export * from './stores/storage.js';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA"}
@@ -0,0 +1,7 @@
1
+ export * from './interface.js';
2
+ export * from './manager.js';
3
+ export * from './schemas.js';
4
+ export * from './service.js';
5
+ export * from './stores/memory.js';
6
+ export * from './stores/storage.js';
7
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/cache/index.ts"],"names":[],"mappings":"AAAA,cAAc,gBAAgB,CAAA;AAC9B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,cAAc,CAAA;AAC5B,cAAc,oBAAoB,CAAA;AAClC,cAAc,qBAAqB,CAAA"}
@@ -0,0 +1,57 @@
1
+ /**
2
+ * Interface definition for Cache Stores in @ansango/lastfm-api
3
+ */
4
+ export interface CacheStoreStats {
5
+ hits: number;
6
+ misses: number;
7
+ size: number;
8
+ }
9
+ export interface CacheStore {
10
+ /**
11
+ * Retrieve a cached value by key
12
+ */
13
+ get<T = unknown>(key: string): Promise<T | undefined> | T | undefined;
14
+ /**
15
+ * Store a value in the cache with an optional TTL in milliseconds
16
+ */
17
+ set<T = unknown>(key: string, value: T, ttlMs?: number): Promise<void> | void;
18
+ /**
19
+ * Remove a specific key from the cache
20
+ */
21
+ delete(key: string): Promise<boolean> | boolean;
22
+ /**
23
+ * Clear all cached values
24
+ */
25
+ clear(): Promise<void> | void;
26
+ /**
27
+ * Check if a non-expired key exists in the cache
28
+ */
29
+ has(key: string): Promise<boolean> | boolean;
30
+ /**
31
+ * Get cache metrics if supported
32
+ */
33
+ stats?(): CacheStoreStats;
34
+ }
35
+ export interface CacheOptions {
36
+ /**
37
+ * Custom cache store implementation (defaults to MemoryCacheStore)
38
+ */
39
+ store?: CacheStore;
40
+ /**
41
+ * Default TTL in milliseconds for all read requests (default: 300,000 ms / 5 minutes)
42
+ */
43
+ defaultTtlMs?: number;
44
+ /**
45
+ * Granular TTL overrides by namespace (e.g. { artist: 86_400_000, user: 60_000 })
46
+ */
47
+ ttlByNamespace?: Record<string, number>;
48
+ /**
49
+ * Granular TTL overrides by method (e.g. { 'user.getRecentTracks': 10_000 })
50
+ */
51
+ ttlByMethod?: Record<string, number>;
52
+ /**
53
+ * Whether caching is enabled (default: true)
54
+ */
55
+ enabled?: boolean;
56
+ }
57
+ //# sourceMappingURL=interface.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/cache/interface.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,MAAM,WAAW,eAAe;IAC/B,IAAI,EAAE,MAAM,CAAA;IACZ,MAAM,EAAE,MAAM,CAAA;IACd,IAAI,EAAE,MAAM,CAAA;CACZ;AAED,MAAM,WAAW,UAAU;IAC1B;;OAEG;IACH,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC,GAAG,CAAC,GAAG,SAAS,CAAA;IAErE;;OAEG;IACH,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAE7E;;OAEG;IACH,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;IAE/C;;OAEG;IACH,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;IAE7B;;OAEG;IACH,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;IAE5C;;OAEG;IACH,KAAK,CAAC,IAAI,eAAe,CAAA;CACzB;AAED,MAAM,WAAW,YAAY;IAC5B;;OAEG;IACH,KAAK,CAAC,EAAE,UAAU,CAAA;IAElB;;OAEG;IACH,YAAY,CAAC,EAAE,MAAM,CAAA;IAErB;;OAEG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEvC;;OAEG;IACH,WAAW,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAEpC;;OAEG;IACH,OAAO,CAAC,EAAE,OAAO,CAAA;CACjB"}
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Interface definition for Cache Stores in @ansango/lastfm-api
3
+ */
4
+ export {};
5
+ //# sourceMappingURL=interface.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"interface.js","sourceRoot":"","sources":["../../src/cache/interface.ts"],"names":[],"mappings":"AAAA;;GAEG"}
@@ -0,0 +1,19 @@
1
+ import type { CacheOptions, CacheStoreStats } from './interface.js';
2
+ export declare class CacheManager {
3
+ private readonly store;
4
+ private readonly defaultTtlMs;
5
+ private readonly ttlByNamespace;
6
+ private readonly ttlByMethod;
7
+ private readonly enabled;
8
+ constructor(options?: CacheOptions);
9
+ isEnabled(): boolean;
10
+ resolveTtl(methodId?: string): number;
11
+ wrap<T>(key: string, fetcherFn: () => Promise<T>, ttlMs?: number): Promise<T>;
12
+ get<T = unknown>(key: string): Promise<T | undefined>;
13
+ set<T = unknown>(key: string, value: T, ttlMs?: number): Promise<void>;
14
+ delete(key: string): Promise<boolean>;
15
+ clear(): Promise<void>;
16
+ has(key: string): Promise<boolean>;
17
+ stats(): CacheStoreStats | undefined;
18
+ }
19
+ //# sourceMappingURL=manager.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../src/cache/manager.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAc,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAG/E,qBAAa,YAAY;IACxB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAY;IAClC,OAAO,CAAC,QAAQ,CAAC,YAAY,CAAQ;IACrC,OAAO,CAAC,QAAQ,CAAC,cAAc,CAAwB;IACvD,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAwB;IACpD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,GAAE,YAAiB;IAQ/B,SAAS,IAAI,OAAO;IAIpB,UAAU,CAAC,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM;IAiB/B,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,CAAC;IAe7E,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,CAAC,GAAG,SAAS,CAAC;IAIrD,GAAG,CAAC,CAAC,GAAG,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,KAAK,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAItE,MAAM,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIrC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAItB,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAIxC,KAAK,IAAI,eAAe,GAAG,SAAS;CAG3C"}
@@ -0,0 +1,63 @@
1
+ import { MemoryCacheStore } from './stores/memory.js';
2
+ export class CacheManager {
3
+ store;
4
+ defaultTtlMs;
5
+ ttlByNamespace;
6
+ ttlByMethod;
7
+ enabled;
8
+ constructor(options = {}) {
9
+ this.store = options.store ?? new MemoryCacheStore({ defaultTtlMs: options.defaultTtlMs });
10
+ this.defaultTtlMs = options.defaultTtlMs ?? 300_000;
11
+ this.ttlByNamespace = options.ttlByNamespace ?? {};
12
+ this.ttlByMethod = options.ttlByMethod ?? {};
13
+ this.enabled = options.enabled ?? true;
14
+ }
15
+ isEnabled() {
16
+ return this.enabled;
17
+ }
18
+ resolveTtl(methodId) {
19
+ if (!methodId)
20
+ return this.defaultTtlMs;
21
+ // 1. Direct method match (e.g. 'user.getRecentTracks' or 'user.getInfo')
22
+ if (this.ttlByMethod[methodId] !== undefined) {
23
+ return this.ttlByMethod[methodId];
24
+ }
25
+ // 2. Namespace match (e.g. 'user', 'artist', 'album')
26
+ const [ns] = methodId.split('.');
27
+ if (ns && this.ttlByNamespace[ns] !== undefined) {
28
+ return this.ttlByNamespace[ns];
29
+ }
30
+ return this.defaultTtlMs;
31
+ }
32
+ async wrap(key, fetcherFn, ttlMs) {
33
+ if (!this.enabled) {
34
+ return fetcherFn();
35
+ }
36
+ const cached = await this.store.get(key);
37
+ if (cached !== undefined) {
38
+ return cached;
39
+ }
40
+ const fresh = await fetcherFn();
41
+ await this.store.set(key, fresh, ttlMs ?? this.defaultTtlMs);
42
+ return fresh;
43
+ }
44
+ async get(key) {
45
+ return this.store.get(key);
46
+ }
47
+ async set(key, value, ttlMs) {
48
+ return this.store.set(key, value, ttlMs ?? this.defaultTtlMs);
49
+ }
50
+ async delete(key) {
51
+ return this.store.delete(key);
52
+ }
53
+ async clear() {
54
+ return this.store.clear();
55
+ }
56
+ async has(key) {
57
+ return this.store.has(key);
58
+ }
59
+ stats() {
60
+ return this.store.stats?.();
61
+ }
62
+ }
63
+ //# sourceMappingURL=manager.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manager.js","sourceRoot":"","sources":["../../src/cache/manager.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,gBAAgB,EAAE,MAAM,oBAAoB,CAAA;AAErD,MAAM,OAAO,YAAY;IACP,KAAK,CAAY;IACjB,YAAY,CAAQ;IACpB,cAAc,CAAwB;IACtC,WAAW,CAAwB;IACnC,OAAO,CAAS;IAEjC,YAAY,UAAwB,EAAE;QACrC,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,IAAI,IAAI,gBAAgB,CAAC,EAAE,YAAY,EAAE,OAAO,CAAC,YAAY,EAAE,CAAC,CAAA;QAC1F,IAAI,CAAC,YAAY,GAAG,OAAO,CAAC,YAAY,IAAI,OAAO,CAAA;QACnD,IAAI,CAAC,cAAc,GAAG,OAAO,CAAC,cAAc,IAAI,EAAE,CAAA;QAClD,IAAI,CAAC,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAA;QAC5C,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,IAAI,CAAA;IACvC,CAAC;IAEM,SAAS;QACf,OAAO,IAAI,CAAC,OAAO,CAAA;IACpB,CAAC;IAEM,UAAU,CAAC,QAAiB;QAClC,IAAI,CAAC,QAAQ;YAAE,OAAO,IAAI,CAAC,YAAY,CAAA;QAEvC,yEAAyE;QACzE,IAAI,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,KAAK,SAAS,EAAE,CAAC;YAC9C,OAAO,IAAI,CAAC,WAAW,CAAC,QAAQ,CAAC,CAAA;QAClC,CAAC;QAED,sDAAsD;QACtD,MAAM,CAAC,EAAE,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;QAChC,IAAI,EAAE,IAAI,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,KAAK,SAAS,EAAE,CAAC;YACjD,OAAO,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC,CAAA;QAC/B,CAAC;QAED,OAAO,IAAI,CAAC,YAAY,CAAA;IACzB,CAAC;IAEM,KAAK,CAAC,IAAI,CAAI,GAAW,EAAE,SAA2B,EAAE,KAAc;QAC5E,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC;YACnB,OAAO,SAAS,EAAE,CAAA;QACnB,CAAC;QAED,MAAM,MAAM,GAAG,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAI,GAAG,CAAC,CAAA;QAC3C,IAAI,MAAM,KAAK,SAAS,EAAE,CAAC;YAC1B,OAAO,MAAM,CAAA;QACd,CAAC;QAED,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAA;QAC/B,MAAM,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC,CAAA;QAC5D,OAAO,KAAK,CAAA;IACb,CAAC;IAEM,KAAK,CAAC,GAAG,CAAc,GAAW;QACxC,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAI,GAAG,CAAC,CAAA;IAC9B,CAAC;IAEM,KAAK,CAAC,GAAG,CAAc,GAAW,EAAE,KAAQ,EAAE,KAAc;QAClE,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC,CAAA;IAC9D,CAAC;IAEM,KAAK,CAAC,MAAM,CAAC,GAAW;QAC9B,OAAO,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,GAAG,CAAC,CAAA;IAC9B,CAAC;IAEM,KAAK,CAAC,KAAK;QACjB,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,CAAA;IAC1B,CAAC;IAEM,KAAK,CAAC,GAAG,CAAC,GAAW;QAC3B,OAAO,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,CAAC,CAAA;IAC3B,CAAC;IAEM,KAAK;QACX,OAAO,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE,CAAA;IAC5B,CAAC;CACD"}