@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.
- package/CHANGELOG.md +65 -0
- package/README.md +254 -21
- package/dist/cache/index.d.ts +7 -0
- package/dist/cache/index.d.ts.map +1 -0
- package/dist/cache/index.js +7 -0
- package/dist/cache/index.js.map +1 -0
- package/dist/cache/interface.d.ts +57 -0
- package/dist/cache/interface.d.ts.map +1 -0
- package/dist/cache/interface.js +5 -0
- package/dist/cache/interface.js.map +1 -0
- package/dist/cache/manager.d.ts +19 -0
- package/dist/cache/manager.d.ts.map +1 -0
- package/dist/cache/manager.js +63 -0
- package/dist/cache/manager.js.map +1 -0
- package/dist/cache/schemas.d.ts +15 -0
- package/dist/cache/schemas.d.ts.map +1 -0
- package/dist/cache/schemas.js +13 -0
- package/dist/cache/schemas.js.map +1 -0
- package/dist/cache/service.d.ts +13 -0
- package/dist/cache/service.d.ts.map +1 -0
- package/dist/cache/service.js +12 -0
- package/dist/cache/service.js.map +1 -0
- package/dist/cache/stores/memory.d.ts +33 -0
- package/dist/cache/stores/memory.d.ts.map +1 -0
- package/dist/cache/stores/memory.js +85 -0
- package/dist/cache/stores/memory.js.map +1 -0
- package/dist/cache/stores/storage.d.ts +42 -0
- package/dist/cache/stores/storage.d.ts.map +1 -0
- package/dist/cache/stores/storage.js +109 -0
- package/dist/cache/stores/storage.js.map +1 -0
- package/dist/client.d.ts +12 -1
- package/dist/client.d.ts.map +1 -1
- package/dist/client.js +21 -1
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +4 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +13 -0
- package/dist/config.js.map +1 -1
- package/dist/core/canonical-methods.d.ts +25 -0
- package/dist/core/canonical-methods.d.ts.map +1 -0
- package/dist/core/canonical-methods.js +88 -0
- package/dist/core/canonical-methods.js.map +1 -0
- package/dist/core/client.d.ts +33 -0
- package/dist/core/client.d.ts.map +1 -0
- package/dist/core/client.js +48 -0
- package/dist/core/client.js.map +1 -0
- package/dist/core/index.d.ts +6 -0
- package/dist/core/index.d.ts.map +1 -0
- package/dist/core/index.js +6 -0
- package/dist/core/index.js.map +1 -0
- package/dist/core/pagination.d.ts +59 -0
- package/dist/core/pagination.d.ts.map +1 -0
- package/dist/core/pagination.js +93 -0
- package/dist/core/pagination.js.map +1 -0
- package/dist/core/schemas/album.schemas.d.ts.map +1 -0
- package/dist/{services → core/schemas}/album.schemas.js +1 -1
- package/dist/core/schemas/album.schemas.js.map +1 -0
- package/dist/core/schemas/artist.schemas.d.ts.map +1 -0
- package/dist/{services → core/schemas}/artist.schemas.js +1 -1
- package/dist/core/schemas/artist.schemas.js.map +1 -0
- package/dist/core/schemas/auth.schemas.d.ts.map +1 -0
- package/dist/core/schemas/auth.schemas.js.map +1 -0
- package/dist/core/schemas/base/base.entities.schemas.d.ts.map +1 -0
- package/dist/core/schemas/base/base.entities.schemas.js.map +1 -0
- package/dist/core/schemas/base/base.entity-names.schemas.d.ts.map +1 -0
- package/dist/core/schemas/base/base.entity-names.schemas.js.map +1 -0
- package/dist/core/schemas/base/base.metadata.schemas.d.ts.map +1 -0
- package/dist/core/schemas/base/base.metadata.schemas.js.map +1 -0
- package/dist/core/schemas/base/base.pagination.schemas.d.ts.map +1 -0
- package/dist/core/schemas/base/base.pagination.schemas.js.map +1 -0
- package/dist/core/schemas/base/base.primitives.schemas.d.ts.map +1 -0
- package/dist/core/schemas/base/base.primitives.schemas.js.map +1 -0
- package/dist/core/schemas/base/index.d.ts.map +1 -0
- package/dist/core/schemas/base/index.js.map +1 -0
- package/dist/core/schemas/chart.schemas.d.ts.map +1 -0
- package/dist/{services → core/schemas}/chart.schemas.js +1 -1
- package/dist/core/schemas/chart.schemas.js.map +1 -0
- package/dist/core/schemas/geo.schemas.d.ts.map +1 -0
- package/dist/{services → core/schemas}/geo.schemas.js +1 -1
- package/dist/core/schemas/geo.schemas.js.map +1 -0
- package/dist/core/schemas/index.d.ts +11 -0
- package/dist/core/schemas/index.d.ts.map +1 -0
- package/dist/core/schemas/index.js +11 -0
- package/dist/core/schemas/index.js.map +1 -0
- package/dist/core/schemas/library.schemas.d.ts.map +1 -0
- package/dist/{services → core/schemas}/library.schemas.js +1 -1
- package/dist/core/schemas/library.schemas.js.map +1 -0
- package/dist/core/schemas/tag.schemas.d.ts.map +1 -0
- package/dist/{services → core/schemas}/tag.schemas.js +1 -1
- package/dist/core/schemas/tag.schemas.js.map +1 -0
- package/dist/core/schemas/track.schemas.d.ts.map +1 -0
- package/dist/{services → core/schemas}/track.schemas.js +1 -1
- package/dist/core/schemas/track.schemas.js.map +1 -0
- package/dist/core/schemas/user.schemas.d.ts.map +1 -0
- package/dist/{services → core/schemas}/user.schemas.js +1 -1
- package/dist/core/schemas/user.schemas.js.map +1 -0
- package/dist/{services → core/services}/album.d.ts +2 -2
- package/dist/core/services/album.d.ts.map +1 -0
- package/dist/{services → core/services}/album.js +5 -5
- package/dist/core/services/album.js.map +1 -0
- package/dist/{services → core/services}/artist.d.ts +2 -2
- package/dist/core/services/artist.d.ts.map +1 -0
- package/dist/{services → core/services}/artist.js +9 -9
- package/dist/core/services/artist.js.map +1 -0
- package/dist/{services → core/services}/auth.d.ts +2 -2
- package/dist/core/services/auth.d.ts.map +1 -0
- package/dist/{services → core/services}/auth.js +1 -1
- package/dist/core/services/auth.js.map +1 -0
- package/dist/{services → core/services}/chart.d.ts +2 -2
- package/dist/core/services/chart.d.ts.map +1 -0
- package/dist/core/services/chart.js +9 -0
- package/dist/core/services/chart.js.map +1 -0
- package/dist/{services → core/services}/geo.d.ts +2 -2
- package/dist/core/services/geo.d.ts.map +1 -0
- package/dist/core/services/geo.js +8 -0
- package/dist/core/services/geo.js.map +1 -0
- package/dist/core/services/index.d.ts +10 -0
- package/dist/core/services/index.d.ts.map +1 -0
- package/dist/core/services/index.js +10 -0
- package/dist/core/services/index.js.map +1 -0
- package/dist/{services → core/services}/library.d.ts +2 -2
- package/dist/core/services/library.d.ts.map +1 -0
- package/dist/core/services/library.js +7 -0
- package/dist/core/services/library.js.map +1 -0
- package/dist/{services → core/services}/tag.d.ts +2 -2
- package/dist/core/services/tag.d.ts.map +1 -0
- package/dist/{services → core/services}/tag.js +8 -8
- package/dist/core/services/tag.js.map +1 -0
- package/dist/{services → core/services}/track.d.ts +2 -2
- package/dist/core/services/track.d.ts.map +1 -0
- package/dist/{services → core/services}/track.js +7 -7
- package/dist/core/services/track.js.map +1 -0
- package/dist/{services → core/services}/track.utils.d.ts +2 -2
- package/dist/core/services/track.utils.d.ts.map +1 -0
- package/dist/core/services/track.utils.js.map +1 -0
- package/dist/{services → core/services}/user.d.ts +2 -2
- package/dist/core/services/user.d.ts.map +1 -0
- package/dist/core/services/user.js +19 -0
- package/dist/core/services/user.js.map +1 -0
- package/dist/entrypoints/album.d.ts +3 -3
- package/dist/entrypoints/album.d.ts.map +1 -1
- package/dist/entrypoints/album.js +2 -2
- package/dist/entrypoints/album.js.map +1 -1
- package/dist/entrypoints/album.schemas.d.ts +2 -1
- package/dist/entrypoints/album.schemas.d.ts.map +1 -1
- package/dist/entrypoints/album.schemas.js +1 -2
- package/dist/entrypoints/album.schemas.js.map +1 -1
- package/dist/entrypoints/artist.d.ts +3 -3
- package/dist/entrypoints/artist.d.ts.map +1 -1
- package/dist/entrypoints/artist.js +2 -2
- package/dist/entrypoints/artist.js.map +1 -1
- package/dist/entrypoints/artist.schemas.d.ts +2 -1
- package/dist/entrypoints/artist.schemas.d.ts.map +1 -1
- package/dist/entrypoints/artist.schemas.js +1 -2
- package/dist/entrypoints/artist.schemas.js.map +1 -1
- package/dist/entrypoints/auth.d.ts +3 -3
- package/dist/entrypoints/auth.d.ts.map +1 -1
- package/dist/entrypoints/auth.js +2 -2
- package/dist/entrypoints/auth.js.map +1 -1
- package/dist/entrypoints/auth.schemas.d.ts +2 -1
- package/dist/entrypoints/auth.schemas.d.ts.map +1 -1
- package/dist/entrypoints/auth.schemas.js +1 -2
- package/dist/entrypoints/auth.schemas.js.map +1 -1
- package/dist/entrypoints/base.schemas.d.ts +2 -1
- package/dist/entrypoints/base.schemas.d.ts.map +1 -1
- package/dist/entrypoints/base.schemas.js +1 -2
- package/dist/entrypoints/base.schemas.js.map +1 -1
- package/dist/entrypoints/cache.d.ts +2 -0
- package/dist/entrypoints/cache.d.ts.map +1 -0
- package/dist/entrypoints/cache.js +2 -0
- package/dist/entrypoints/cache.js.map +1 -0
- package/dist/entrypoints/cache.schemas.d.ts +2 -0
- package/dist/entrypoints/cache.schemas.d.ts.map +1 -0
- package/dist/entrypoints/cache.schemas.js +2 -0
- package/dist/entrypoints/cache.schemas.js.map +1 -0
- package/dist/entrypoints/chart.d.ts +3 -3
- package/dist/entrypoints/chart.d.ts.map +1 -1
- package/dist/entrypoints/chart.js +2 -2
- package/dist/entrypoints/chart.js.map +1 -1
- package/dist/entrypoints/chart.schemas.d.ts +2 -1
- package/dist/entrypoints/chart.schemas.d.ts.map +1 -1
- package/dist/entrypoints/chart.schemas.js +1 -2
- package/dist/entrypoints/chart.schemas.js.map +1 -1
- package/dist/entrypoints/core.d.ts +5 -0
- package/dist/entrypoints/core.d.ts.map +1 -0
- package/dist/entrypoints/core.js +5 -0
- package/dist/entrypoints/core.js.map +1 -0
- package/dist/entrypoints/core.schemas.d.ts +3 -0
- package/dist/entrypoints/core.schemas.d.ts.map +1 -0
- package/dist/entrypoints/core.schemas.js +2 -0
- package/dist/entrypoints/core.schemas.js.map +1 -0
- package/dist/entrypoints/exporter.d.ts +3 -0
- package/dist/entrypoints/exporter.d.ts.map +1 -0
- package/dist/entrypoints/exporter.js +3 -0
- package/dist/entrypoints/exporter.js.map +1 -0
- package/dist/entrypoints/exporter.schemas.d.ts +3 -0
- package/dist/entrypoints/exporter.schemas.d.ts.map +1 -0
- package/dist/entrypoints/exporter.schemas.js +2 -0
- package/dist/entrypoints/exporter.schemas.js.map +1 -0
- package/dist/entrypoints/geo.d.ts +3 -3
- package/dist/entrypoints/geo.d.ts.map +1 -1
- package/dist/entrypoints/geo.js +2 -2
- package/dist/entrypoints/geo.js.map +1 -1
- package/dist/entrypoints/geo.schemas.d.ts +2 -1
- package/dist/entrypoints/geo.schemas.d.ts.map +1 -1
- package/dist/entrypoints/geo.schemas.js +1 -2
- package/dist/entrypoints/geo.schemas.js.map +1 -1
- package/dist/entrypoints/insights.d.ts +3 -3
- package/dist/entrypoints/insights.d.ts.map +1 -1
- package/dist/entrypoints/insights.js +2 -2
- package/dist/entrypoints/insights.js.map +1 -1
- package/dist/entrypoints/insights.schemas.d.ts +2 -1
- package/dist/entrypoints/insights.schemas.d.ts.map +1 -1
- package/dist/entrypoints/insights.schemas.js +1 -2
- package/dist/entrypoints/insights.schemas.js.map +1 -1
- package/dist/entrypoints/library.d.ts +3 -3
- package/dist/entrypoints/library.d.ts.map +1 -1
- package/dist/entrypoints/library.js +2 -2
- package/dist/entrypoints/library.js.map +1 -1
- package/dist/entrypoints/library.schemas.d.ts +2 -1
- package/dist/entrypoints/library.schemas.d.ts.map +1 -1
- package/dist/entrypoints/library.schemas.js +1 -2
- package/dist/entrypoints/library.schemas.js.map +1 -1
- package/dist/entrypoints/playlists.d.ts +3 -0
- package/dist/entrypoints/playlists.d.ts.map +1 -0
- package/dist/entrypoints/playlists.js +3 -0
- package/dist/entrypoints/playlists.js.map +1 -0
- package/dist/entrypoints/playlists.schemas.d.ts +3 -0
- package/dist/entrypoints/playlists.schemas.d.ts.map +1 -0
- package/dist/entrypoints/playlists.schemas.js +2 -0
- package/dist/entrypoints/playlists.schemas.js.map +1 -0
- package/dist/entrypoints/reports.d.ts +4 -0
- package/dist/entrypoints/reports.d.ts.map +1 -0
- package/dist/entrypoints/reports.js +3 -0
- package/dist/entrypoints/reports.js.map +1 -0
- package/dist/entrypoints/reports.schemas.d.ts +3 -0
- package/dist/entrypoints/reports.schemas.d.ts.map +1 -0
- package/dist/entrypoints/reports.schemas.js +2 -0
- package/dist/entrypoints/reports.schemas.js.map +1 -0
- package/dist/entrypoints/tag.d.ts +3 -3
- package/dist/entrypoints/tag.d.ts.map +1 -1
- package/dist/entrypoints/tag.js +2 -2
- package/dist/entrypoints/tag.js.map +1 -1
- package/dist/entrypoints/tag.schemas.d.ts +2 -1
- package/dist/entrypoints/tag.schemas.d.ts.map +1 -1
- package/dist/entrypoints/tag.schemas.js +1 -2
- package/dist/entrypoints/tag.schemas.js.map +1 -1
- package/dist/entrypoints/track.d.ts +3 -3
- package/dist/entrypoints/track.d.ts.map +1 -1
- package/dist/entrypoints/track.js +2 -2
- package/dist/entrypoints/track.js.map +1 -1
- package/dist/entrypoints/track.schemas.d.ts +2 -1
- package/dist/entrypoints/track.schemas.d.ts.map +1 -1
- package/dist/entrypoints/track.schemas.js +1 -2
- package/dist/entrypoints/track.schemas.js.map +1 -1
- package/dist/entrypoints/user.d.ts +3 -3
- package/dist/entrypoints/user.d.ts.map +1 -1
- package/dist/entrypoints/user.js +2 -2
- package/dist/entrypoints/user.js.map +1 -1
- package/dist/entrypoints/user.schemas.d.ts +2 -1
- package/dist/entrypoints/user.schemas.d.ts.map +1 -1
- package/dist/entrypoints/user.schemas.js +1 -2
- package/dist/entrypoints/user.schemas.js.map +1 -1
- package/dist/entrypoints/watcher.d.ts +2 -0
- package/dist/entrypoints/watcher.d.ts.map +1 -0
- package/dist/entrypoints/watcher.js +2 -0
- package/dist/entrypoints/watcher.js.map +1 -0
- package/dist/entrypoints/watcher.schemas.d.ts +2 -0
- package/dist/entrypoints/watcher.schemas.d.ts.map +1 -0
- package/dist/entrypoints/watcher.schemas.js +2 -0
- package/dist/entrypoints/watcher.schemas.js.map +1 -0
- package/dist/exporter/engines/library.d.ts +4 -0
- package/dist/exporter/engines/library.d.ts.map +1 -0
- package/dist/exporter/engines/library.js +34 -0
- package/dist/exporter/engines/library.js.map +1 -0
- package/dist/exporter/engines/loved.d.ts +4 -0
- package/dist/exporter/engines/loved.d.ts.map +1 -0
- package/dist/exporter/engines/loved.js +35 -0
- package/dist/exporter/engines/loved.js.map +1 -0
- package/dist/exporter/engines/scrobbles.d.ts +4 -0
- package/dist/exporter/engines/scrobbles.d.ts.map +1 -0
- package/dist/exporter/engines/scrobbles.js +74 -0
- package/dist/exporter/engines/scrobbles.js.map +1 -0
- package/dist/exporter/formats/csv.d.ts +5 -0
- package/dist/exporter/formats/csv.d.ts.map +1 -0
- package/dist/exporter/formats/csv.js +35 -0
- package/dist/exporter/formats/csv.js.map +1 -0
- package/dist/exporter/formats/jsonl.d.ts +2 -0
- package/dist/exporter/formats/jsonl.d.ts.map +1 -0
- package/dist/exporter/formats/jsonl.js +4 -0
- package/dist/exporter/formats/jsonl.js.map +1 -0
- package/dist/exporter/formats/listenbrainz.d.ts +3 -0
- package/dist/exporter/formats/listenbrainz.d.ts.map +1 -0
- package/dist/exporter/formats/listenbrainz.js +19 -0
- package/dist/exporter/formats/listenbrainz.js.map +1 -0
- package/dist/exporter/index.d.ts +6 -0
- package/dist/exporter/index.d.ts.map +1 -0
- package/dist/exporter/index.js +6 -0
- package/dist/exporter/index.js.map +1 -0
- package/dist/exporter/schemas.d.ts +291 -0
- package/dist/exporter/schemas.d.ts.map +1 -0
- package/dist/exporter/schemas.js +81 -0
- package/dist/exporter/schemas.js.map +1 -0
- package/dist/exporter/service.d.ts +30 -0
- package/dist/exporter/service.d.ts.map +1 -0
- package/dist/exporter/service.js +11 -0
- package/dist/exporter/service.js.map +1 -0
- package/dist/index.d.ts +18 -24
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +21 -16
- package/dist/index.js.map +1 -1
- package/dist/insights/algorithms/album-habits.d.ts +7 -0
- package/dist/insights/algorithms/album-habits.d.ts.map +1 -0
- package/dist/insights/algorithms/album-habits.js +154 -0
- package/dist/insights/algorithms/album-habits.js.map +1 -0
- package/dist/{services/insights → insights/algorithms}/binges.d.ts +1 -1
- package/dist/insights/algorithms/binges.d.ts.map +1 -0
- package/dist/{services/insights → insights/algorithms}/binges.js +2 -2
- package/dist/insights/algorithms/binges.js.map +1 -0
- package/dist/{services/insights → insights/algorithms}/compare.d.ts +1 -1
- package/dist/insights/algorithms/compare.d.ts.map +1 -0
- package/dist/{services/insights → insights/algorithms}/compare.js +3 -3
- package/dist/insights/algorithms/compare.js.map +1 -0
- package/dist/insights/algorithms/decay.d.ts +11 -0
- package/dist/insights/algorithms/decay.d.ts.map +1 -0
- package/dist/insights/algorithms/decay.js +154 -0
- package/dist/insights/algorithms/decay.js.map +1 -0
- package/dist/{services/insights → insights/algorithms}/discoveries.d.ts +1 -1
- package/dist/insights/algorithms/discoveries.d.ts.map +1 -0
- package/dist/{services/insights → insights/algorithms}/discoveries.js +2 -2
- package/dist/insights/algorithms/discoveries.js.map +1 -0
- package/dist/insights/algorithms/genres.d.ts +11 -0
- package/dist/insights/algorithms/genres.d.ts.map +1 -0
- package/dist/insights/algorithms/genres.js +201 -0
- package/dist/insights/algorithms/genres.js.map +1 -0
- package/dist/insights/algorithms/group.d.ts +8 -0
- package/dist/insights/algorithms/group.d.ts.map +1 -0
- package/dist/insights/algorithms/group.js +127 -0
- package/dist/insights/algorithms/group.js.map +1 -0
- package/dist/{services/insights → insights/algorithms}/hours.d.ts +1 -1
- package/dist/insights/algorithms/hours.d.ts.map +1 -0
- package/dist/{services/insights → insights/algorithms}/hours.js +2 -2
- package/dist/insights/algorithms/hours.js.map +1 -0
- package/dist/{services/insights → insights/algorithms}/mood.d.ts +1 -1
- package/dist/insights/algorithms/mood.d.ts.map +1 -0
- package/dist/{services/insights → insights/algorithms}/mood.js +4 -4
- package/dist/insights/algorithms/mood.js.map +1 -0
- package/dist/{services/insights → insights/algorithms}/now-playing.d.ts +1 -1
- package/dist/{services/insights → insights/algorithms}/now-playing.d.ts.map +1 -1
- package/dist/{services/insights → insights/algorithms}/now-playing.js +2 -2
- package/dist/insights/algorithms/now-playing.js.map +1 -0
- package/dist/insights/algorithms/obscurity.d.ts +27 -0
- package/dist/insights/algorithms/obscurity.d.ts.map +1 -0
- package/dist/insights/algorithms/obscurity.js +158 -0
- package/dist/insights/algorithms/obscurity.js.map +1 -0
- package/dist/{services/insights → insights/algorithms}/personality.d.ts +1 -1
- package/dist/insights/algorithms/personality.d.ts.map +1 -0
- package/dist/{services/insights → insights/algorithms}/personality.js +1 -1
- package/dist/insights/algorithms/personality.js.map +1 -0
- package/dist/insights/algorithms/recommendations.d.ts +11 -0
- package/dist/insights/algorithms/recommendations.d.ts.map +1 -0
- package/dist/insights/algorithms/recommendations.js +121 -0
- package/dist/insights/algorithms/recommendations.js.map +1 -0
- package/dist/insights/algorithms/streaks.d.ts +11 -0
- package/dist/insights/algorithms/streaks.d.ts.map +1 -0
- package/dist/insights/algorithms/streaks.js +178 -0
- package/dist/insights/algorithms/streaks.js.map +1 -0
- package/dist/{services/insights → insights/algorithms}/summary.d.ts +1 -1
- package/dist/insights/algorithms/summary.d.ts.map +1 -0
- package/dist/{services/insights → insights/algorithms}/summary.js +3 -3
- package/dist/insights/algorithms/summary.js.map +1 -0
- package/dist/{services/insights → insights/algorithms}/trends.d.ts +1 -1
- package/dist/insights/algorithms/trends.d.ts.map +1 -0
- package/dist/{services/insights → insights/algorithms}/trends.js +3 -3
- package/dist/insights/algorithms/trends.js.map +1 -0
- package/dist/insights/index.d.ts +3 -0
- package/dist/insights/index.d.ts.map +1 -0
- package/dist/insights/index.js +3 -0
- package/dist/insights/index.js.map +1 -0
- package/dist/insights/lib/binges.d.ts.map +1 -0
- package/dist/insights/lib/binges.js.map +1 -0
- package/dist/insights/lib/compare.d.ts.map +1 -0
- package/dist/insights/lib/compare.js.map +1 -0
- package/dist/insights/lib/discoveries.d.ts.map +1 -0
- package/dist/insights/lib/discoveries.js.map +1 -0
- package/dist/insights/lib/diversity.d.ts.map +1 -0
- package/dist/insights/lib/diversity.js.map +1 -0
- package/dist/insights/lib/hours.d.ts.map +1 -0
- package/dist/insights/lib/hours.js.map +1 -0
- package/dist/insights/lib/mood.d.ts.map +1 -0
- package/dist/insights/lib/mood.js.map +1 -0
- package/dist/{services/insights → insights}/lib/periods.d.ts +1 -1
- package/dist/insights/lib/periods.d.ts.map +1 -0
- package/dist/insights/lib/periods.js.map +1 -0
- package/dist/insights/lib/personality.d.ts.map +1 -0
- package/dist/insights/lib/personality.js.map +1 -0
- package/dist/insights/lib/trends.d.ts.map +1 -0
- package/dist/insights/lib/trends.js.map +1 -0
- package/dist/insights/schemas.d.ts +1415 -0
- package/dist/insights/schemas.d.ts.map +1 -0
- package/dist/{services/insights.schemas.js → insights/schemas.js} +291 -2
- package/dist/insights/schemas.js.map +1 -0
- package/dist/insights/service.d.ts +191 -0
- package/dist/insights/service.d.ts.map +1 -0
- package/dist/insights/service.js +44 -0
- package/dist/insights/service.js.map +1 -0
- package/dist/playlists/formatters/csv.d.ts +3 -0
- package/dist/playlists/formatters/csv.d.ts.map +1 -0
- package/dist/playlists/formatters/csv.js +18 -0
- package/dist/playlists/formatters/csv.js.map +1 -0
- package/dist/playlists/formatters/m3u.d.ts +3 -0
- package/dist/playlists/formatters/m3u.d.ts.map +1 -0
- package/dist/playlists/formatters/m3u.js +10 -0
- package/dist/playlists/formatters/m3u.js.map +1 -0
- package/dist/playlists/formatters/spotifymatch.d.ts +3 -0
- package/dist/playlists/formatters/spotifymatch.d.ts.map +1 -0
- package/dist/playlists/formatters/spotifymatch.js +4 -0
- package/dist/playlists/formatters/spotifymatch.js.map +1 -0
- package/dist/playlists/generators/generator.d.ts +4 -0
- package/dist/playlists/generators/generator.d.ts.map +1 -0
- package/dist/playlists/generators/generator.js +158 -0
- package/dist/playlists/generators/generator.js.map +1 -0
- package/dist/playlists/index.d.ts +6 -0
- package/dist/playlists/index.d.ts.map +1 -0
- package/dist/playlists/index.js +6 -0
- package/dist/playlists/index.js.map +1 -0
- package/dist/playlists/schemas.d.ts +150 -0
- package/dist/playlists/schemas.d.ts.map +1 -0
- package/dist/playlists/schemas.js +53 -0
- package/dist/playlists/schemas.js.map +1 -0
- package/dist/playlists/service.d.ts +28 -0
- package/dist/playlists/service.d.ts.map +1 -0
- package/dist/playlists/service.js +27 -0
- package/dist/playlists/service.js.map +1 -0
- package/dist/reports/generators/digest.d.ts +4 -0
- package/dist/reports/generators/digest.d.ts.map +1 -0
- package/dist/reports/generators/digest.js +95 -0
- package/dist/reports/generators/digest.js.map +1 -0
- package/dist/reports/generators/milestones.d.ts +4 -0
- package/dist/reports/generators/milestones.d.ts.map +1 -0
- package/dist/reports/generators/milestones.js +59 -0
- package/dist/reports/generators/milestones.js.map +1 -0
- package/dist/reports/generators/wrapped.d.ts +4 -0
- package/dist/reports/generators/wrapped.d.ts.map +1 -0
- package/dist/reports/generators/wrapped.js +179 -0
- package/dist/reports/generators/wrapped.js.map +1 -0
- package/dist/reports/index.d.ts +3 -0
- package/dist/reports/index.d.ts.map +1 -0
- package/dist/reports/index.js +3 -0
- package/dist/reports/index.js.map +1 -0
- package/dist/reports/schemas.d.ts +244 -0
- package/dist/reports/schemas.d.ts.map +1 -0
- package/dist/reports/schemas.js +92 -0
- package/dist/reports/schemas.js.map +1 -0
- package/dist/reports/service.d.ts +30 -0
- package/dist/reports/service.d.ts.map +1 -0
- package/dist/reports/service.js +11 -0
- package/dist/reports/service.js.map +1 -0
- package/dist/utils.d.ts +3 -2
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +19 -2
- package/dist/utils.js.map +1 -1
- package/dist/watcher/emitter.d.ts +14 -0
- package/dist/watcher/emitter.d.ts.map +1 -0
- package/dist/watcher/emitter.js +72 -0
- package/dist/watcher/emitter.js.map +1 -0
- package/dist/watcher/index.d.ts +5 -0
- package/dist/watcher/index.d.ts.map +1 -0
- package/dist/watcher/index.js +5 -0
- package/dist/watcher/index.js.map +1 -0
- package/dist/watcher/schemas.d.ts +39 -0
- package/dist/watcher/schemas.d.ts.map +1 -0
- package/dist/watcher/schemas.js +33 -0
- package/dist/watcher/schemas.js.map +1 -0
- package/dist/watcher/service.d.ts +15 -0
- package/dist/watcher/service.d.ts.map +1 -0
- package/dist/watcher/service.js +8 -0
- package/dist/watcher/service.js.map +1 -0
- package/dist/watcher/watcher.d.ts +35 -0
- package/dist/watcher/watcher.d.ts.map +1 -0
- package/dist/watcher/watcher.js +196 -0
- package/dist/watcher/watcher.js.map +1 -0
- package/package.json +49 -3
- package/dist/services/album.d.ts.map +0 -1
- package/dist/services/album.js.map +0 -1
- package/dist/services/album.schemas.d.ts.map +0 -1
- package/dist/services/album.schemas.js.map +0 -1
- package/dist/services/artist.d.ts.map +0 -1
- package/dist/services/artist.js.map +0 -1
- package/dist/services/artist.schemas.d.ts.map +0 -1
- package/dist/services/artist.schemas.js.map +0 -1
- package/dist/services/auth.d.ts.map +0 -1
- package/dist/services/auth.js.map +0 -1
- package/dist/services/auth.schemas.d.ts.map +0 -1
- package/dist/services/auth.schemas.js.map +0 -1
- package/dist/services/chart.d.ts.map +0 -1
- package/dist/services/chart.js +0 -9
- package/dist/services/chart.js.map +0 -1
- package/dist/services/chart.schemas.d.ts.map +0 -1
- package/dist/services/chart.schemas.js.map +0 -1
- package/dist/services/geo.d.ts.map +0 -1
- package/dist/services/geo.js +0 -8
- package/dist/services/geo.js.map +0 -1
- package/dist/services/geo.schemas.d.ts.map +0 -1
- package/dist/services/geo.schemas.js.map +0 -1
- package/dist/services/index.d.ts +0 -22
- package/dist/services/index.d.ts.map +0 -1
- package/dist/services/index.js +0 -23
- package/dist/services/index.js.map +0 -1
- package/dist/services/insights/binges.d.ts.map +0 -1
- package/dist/services/insights/binges.js.map +0 -1
- package/dist/services/insights/compare.d.ts.map +0 -1
- package/dist/services/insights/compare.js.map +0 -1
- package/dist/services/insights/discoveries.d.ts.map +0 -1
- package/dist/services/insights/discoveries.js.map +0 -1
- package/dist/services/insights/hours.d.ts.map +0 -1
- package/dist/services/insights/hours.js.map +0 -1
- package/dist/services/insights/lib/binges.d.ts.map +0 -1
- package/dist/services/insights/lib/binges.js.map +0 -1
- package/dist/services/insights/lib/compare.d.ts.map +0 -1
- package/dist/services/insights/lib/compare.js.map +0 -1
- package/dist/services/insights/lib/discoveries.d.ts.map +0 -1
- package/dist/services/insights/lib/discoveries.js.map +0 -1
- package/dist/services/insights/lib/diversity.d.ts.map +0 -1
- package/dist/services/insights/lib/diversity.js.map +0 -1
- package/dist/services/insights/lib/hours.d.ts.map +0 -1
- package/dist/services/insights/lib/hours.js.map +0 -1
- package/dist/services/insights/lib/mood.d.ts.map +0 -1
- package/dist/services/insights/lib/mood.js.map +0 -1
- package/dist/services/insights/lib/periods.d.ts.map +0 -1
- package/dist/services/insights/lib/periods.js.map +0 -1
- package/dist/services/insights/lib/personality.d.ts.map +0 -1
- package/dist/services/insights/lib/personality.js.map +0 -1
- package/dist/services/insights/lib/trends.d.ts.map +0 -1
- package/dist/services/insights/lib/trends.js.map +0 -1
- package/dist/services/insights/mood.d.ts.map +0 -1
- package/dist/services/insights/mood.js.map +0 -1
- package/dist/services/insights/now-playing.js.map +0 -1
- package/dist/services/insights/personality.d.ts.map +0 -1
- package/dist/services/insights/personality.js.map +0 -1
- package/dist/services/insights/summary.d.ts.map +0 -1
- package/dist/services/insights/summary.js.map +0 -1
- package/dist/services/insights/trends.d.ts.map +0 -1
- package/dist/services/insights/trends.js.map +0 -1
- package/dist/services/insights.d.ts +0 -96
- package/dist/services/insights.d.ts.map +0 -1
- package/dist/services/insights.js +0 -26
- package/dist/services/insights.js.map +0 -1
- package/dist/services/insights.schemas.d.ts +0 -710
- package/dist/services/insights.schemas.d.ts.map +0 -1
- package/dist/services/insights.schemas.js.map +0 -1
- package/dist/services/library.d.ts.map +0 -1
- package/dist/services/library.js +0 -7
- package/dist/services/library.js.map +0 -1
- package/dist/services/library.schemas.d.ts.map +0 -1
- package/dist/services/library.schemas.js.map +0 -1
- package/dist/services/schemas/base.entities.schemas.d.ts.map +0 -1
- package/dist/services/schemas/base.entities.schemas.js.map +0 -1
- package/dist/services/schemas/base.entity-names.schemas.d.ts.map +0 -1
- package/dist/services/schemas/base.entity-names.schemas.js.map +0 -1
- package/dist/services/schemas/base.metadata.schemas.d.ts.map +0 -1
- package/dist/services/schemas/base.metadata.schemas.js.map +0 -1
- package/dist/services/schemas/base.pagination.schemas.d.ts.map +0 -1
- package/dist/services/schemas/base.pagination.schemas.js.map +0 -1
- package/dist/services/schemas/base.primitives.schemas.d.ts.map +0 -1
- package/dist/services/schemas/base.primitives.schemas.js.map +0 -1
- package/dist/services/schemas/index.d.ts.map +0 -1
- package/dist/services/schemas/index.js.map +0 -1
- package/dist/services/tag.d.ts.map +0 -1
- package/dist/services/tag.js.map +0 -1
- package/dist/services/tag.schemas.d.ts.map +0 -1
- package/dist/services/tag.schemas.js.map +0 -1
- package/dist/services/track.d.ts.map +0 -1
- package/dist/services/track.js.map +0 -1
- package/dist/services/track.schemas.d.ts.map +0 -1
- package/dist/services/track.schemas.js.map +0 -1
- package/dist/services/track.utils.d.ts.map +0 -1
- package/dist/services/track.utils.js.map +0 -1
- package/dist/services/user.d.ts.map +0 -1
- package/dist/services/user.js +0 -19
- package/dist/services/user.js.map +0 -1
- package/dist/services/user.schemas.d.ts.map +0 -1
- package/dist/services/user.schemas.js.map +0 -1
- /package/dist/{services → core/schemas}/album.schemas.d.ts +0 -0
- /package/dist/{services → core/schemas}/artist.schemas.d.ts +0 -0
- /package/dist/{services → core/schemas}/auth.schemas.d.ts +0 -0
- /package/dist/{services → core/schemas}/auth.schemas.js +0 -0
- /package/dist/{services/schemas → core/schemas/base}/base.entities.schemas.d.ts +0 -0
- /package/dist/{services/schemas → core/schemas/base}/base.entities.schemas.js +0 -0
- /package/dist/{services/schemas → core/schemas/base}/base.entity-names.schemas.d.ts +0 -0
- /package/dist/{services/schemas → core/schemas/base}/base.entity-names.schemas.js +0 -0
- /package/dist/{services/schemas → core/schemas/base}/base.metadata.schemas.d.ts +0 -0
- /package/dist/{services/schemas → core/schemas/base}/base.metadata.schemas.js +0 -0
- /package/dist/{services/schemas → core/schemas/base}/base.pagination.schemas.d.ts +0 -0
- /package/dist/{services/schemas → core/schemas/base}/base.pagination.schemas.js +0 -0
- /package/dist/{services/schemas → core/schemas/base}/base.primitives.schemas.d.ts +0 -0
- /package/dist/{services/schemas → core/schemas/base}/base.primitives.schemas.js +0 -0
- /package/dist/{services/schemas → core/schemas/base}/index.d.ts +0 -0
- /package/dist/{services/schemas → core/schemas/base}/index.js +0 -0
- /package/dist/{services → core/schemas}/chart.schemas.d.ts +0 -0
- /package/dist/{services → core/schemas}/geo.schemas.d.ts +0 -0
- /package/dist/{services → core/schemas}/library.schemas.d.ts +0 -0
- /package/dist/{services → core/schemas}/tag.schemas.d.ts +0 -0
- /package/dist/{services → core/schemas}/track.schemas.d.ts +0 -0
- /package/dist/{services → core/schemas}/user.schemas.d.ts +0 -0
- /package/dist/{services → core/services}/track.utils.js +0 -0
- /package/dist/{services/insights → insights}/lib/binges.d.ts +0 -0
- /package/dist/{services/insights → insights}/lib/binges.js +0 -0
- /package/dist/{services/insights → insights}/lib/compare.d.ts +0 -0
- /package/dist/{services/insights → insights}/lib/compare.js +0 -0
- /package/dist/{services/insights → insights}/lib/discoveries.d.ts +0 -0
- /package/dist/{services/insights → insights}/lib/discoveries.js +0 -0
- /package/dist/{services/insights → insights}/lib/diversity.d.ts +0 -0
- /package/dist/{services/insights → insights}/lib/diversity.js +0 -0
- /package/dist/{services/insights → insights}/lib/hours.d.ts +0 -0
- /package/dist/{services/insights → insights}/lib/hours.js +0 -0
- /package/dist/{services/insights → insights}/lib/mood.d.ts +0 -0
- /package/dist/{services/insights → insights}/lib/mood.js +0 -0
- /package/dist/{services/insights → insights}/lib/periods.js +0 -0
- /package/dist/{services/insights → insights}/lib/personality.d.ts +0 -0
- /package/dist/{services/insights → insights}/lib/personality.js +0 -0
- /package/dist/{services/insights → insights}/lib/trends.d.ts +0 -0
- /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**:
|
|
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
|
|
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
|
|
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
|
|
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
|
|
522
|
-
- **InsightsService**:
|
|
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
|
|
603
|
-
canonical Last.fm methods
|
|
604
|
-
|
|
605
|
-
|
|
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
|
|
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
|
-
|
|
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 @@
|
|
|
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 @@
|
|
|
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 @@
|
|
|
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"}
|