@ansango/lastfm-api 3.1.3 → 3.2.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 (168) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/README.md +165 -15
  3. package/dist/client.d.ts +1 -1
  4. package/dist/client.d.ts.map +1 -1
  5. package/dist/client.js +2 -2
  6. package/dist/client.js.map +1 -1
  7. package/dist/config.d.ts.map +1 -1
  8. package/dist/config.js +2 -2
  9. package/dist/config.js.map +1 -1
  10. package/dist/entrypoints/album.d.ts +1 -1
  11. package/dist/entrypoints/album.d.ts.map +1 -1
  12. package/dist/entrypoints/album.js.map +1 -1
  13. package/dist/entrypoints/album.schemas.d.ts.map +1 -1
  14. package/dist/entrypoints/album.schemas.js.map +1 -1
  15. package/dist/entrypoints/artist.d.ts +1 -1
  16. package/dist/entrypoints/artist.d.ts.map +1 -1
  17. package/dist/entrypoints/artist.js.map +1 -1
  18. package/dist/entrypoints/artist.schemas.d.ts.map +1 -1
  19. package/dist/entrypoints/artist.schemas.js.map +1 -1
  20. package/dist/entrypoints/auth.d.ts +1 -1
  21. package/dist/entrypoints/auth.d.ts.map +1 -1
  22. package/dist/entrypoints/auth.js.map +1 -1
  23. package/dist/entrypoints/auth.schemas.d.ts.map +1 -1
  24. package/dist/entrypoints/auth.schemas.js.map +1 -1
  25. package/dist/entrypoints/base.schemas.d.ts.map +1 -1
  26. package/dist/entrypoints/base.schemas.js.map +1 -1
  27. package/dist/entrypoints/chart.d.ts +1 -1
  28. package/dist/entrypoints/chart.d.ts.map +1 -1
  29. package/dist/entrypoints/chart.js.map +1 -1
  30. package/dist/entrypoints/chart.schemas.d.ts.map +1 -1
  31. package/dist/entrypoints/chart.schemas.js.map +1 -1
  32. package/dist/entrypoints/geo.d.ts.map +1 -1
  33. package/dist/entrypoints/geo.js.map +1 -1
  34. package/dist/entrypoints/geo.schemas.d.ts.map +1 -1
  35. package/dist/entrypoints/geo.schemas.js.map +1 -1
  36. package/dist/entrypoints/library.d.ts.map +1 -1
  37. package/dist/entrypoints/library.js.map +1 -1
  38. package/dist/entrypoints/library.schemas.d.ts.map +1 -1
  39. package/dist/entrypoints/library.schemas.js.map +1 -1
  40. package/dist/entrypoints/tag.d.ts.map +1 -1
  41. package/dist/entrypoints/tag.js.map +1 -1
  42. package/dist/entrypoints/tag.schemas.d.ts.map +1 -1
  43. package/dist/entrypoints/tag.schemas.js.map +1 -1
  44. package/dist/entrypoints/track.d.ts.map +1 -1
  45. package/dist/entrypoints/track.js.map +1 -1
  46. package/dist/entrypoints/track.schemas.d.ts.map +1 -1
  47. package/dist/entrypoints/track.schemas.js.map +1 -1
  48. package/dist/entrypoints/user.d.ts.map +1 -1
  49. package/dist/entrypoints/user.js.map +1 -1
  50. package/dist/entrypoints/user.schemas.d.ts.map +1 -1
  51. package/dist/entrypoints/user.schemas.js.map +1 -1
  52. package/dist/index.d.ts +18 -18
  53. package/dist/index.d.ts.map +1 -1
  54. package/dist/index.js +10 -10
  55. package/dist/index.js.map +1 -1
  56. package/dist/services/album.d.ts +43 -1
  57. package/dist/services/album.d.ts.map +1 -1
  58. package/dist/services/album.js +35 -2
  59. package/dist/services/album.js.map +1 -1
  60. package/dist/services/album.schemas.d.ts +51 -12
  61. package/dist/services/album.schemas.d.ts.map +1 -1
  62. package/dist/services/album.schemas.js +48 -10
  63. package/dist/services/album.schemas.js.map +1 -1
  64. package/dist/services/artist.d.ts +50 -1
  65. package/dist/services/artist.d.ts.map +1 -1
  66. package/dist/services/artist.js +34 -2
  67. package/dist/services/artist.js.map +1 -1
  68. package/dist/services/artist.schemas.d.ts +99 -25
  69. package/dist/services/artist.schemas.d.ts.map +1 -1
  70. package/dist/services/artist.schemas.js +125 -60
  71. package/dist/services/artist.schemas.js.map +1 -1
  72. package/dist/services/auth.d.ts +72 -1
  73. package/dist/services/auth.d.ts.map +1 -1
  74. package/dist/services/auth.js +37 -2
  75. package/dist/services/auth.js.map +1 -1
  76. package/dist/services/auth.schemas.d.ts +23 -1
  77. package/dist/services/auth.schemas.d.ts.map +1 -1
  78. package/dist/services/auth.schemas.js +20 -2
  79. package/dist/services/auth.schemas.js.map +1 -1
  80. package/dist/services/chart.d.ts +1 -1
  81. package/dist/services/chart.d.ts.map +1 -1
  82. package/dist/services/chart.js +2 -2
  83. package/dist/services/chart.js.map +1 -1
  84. package/dist/services/chart.schemas.d.ts +6 -6
  85. package/dist/services/chart.schemas.d.ts.map +1 -1
  86. package/dist/services/chart.schemas.js +21 -21
  87. package/dist/services/chart.schemas.js.map +1 -1
  88. package/dist/services/geo.d.ts +1 -1
  89. package/dist/services/geo.d.ts.map +1 -1
  90. package/dist/services/geo.js +2 -2
  91. package/dist/services/geo.js.map +1 -1
  92. package/dist/services/geo.schemas.d.ts +6 -6
  93. package/dist/services/geo.schemas.d.ts.map +1 -1
  94. package/dist/services/geo.schemas.js +17 -17
  95. package/dist/services/geo.schemas.js.map +1 -1
  96. package/dist/services/index.d.ts +12 -12
  97. package/dist/services/index.d.ts.map +1 -1
  98. package/dist/services/index.js +13 -13
  99. package/dist/services/index.js.map +1 -1
  100. package/dist/services/library.d.ts +1 -1
  101. package/dist/services/library.d.ts.map +1 -1
  102. package/dist/services/library.js +2 -2
  103. package/dist/services/library.js.map +1 -1
  104. package/dist/services/library.schemas.d.ts +3 -3
  105. package/dist/services/library.schemas.d.ts.map +1 -1
  106. package/dist/services/library.schemas.js +8 -8
  107. package/dist/services/library.schemas.js.map +1 -1
  108. package/dist/services/schemas/base.entities.schemas.d.ts +3 -3
  109. package/dist/services/schemas/base.entities.schemas.d.ts.map +1 -1
  110. package/dist/services/schemas/base.entities.schemas.js +9 -9
  111. package/dist/services/schemas/base.entities.schemas.js.map +1 -1
  112. package/dist/services/schemas/base.entity-names.schemas.d.ts +1 -1
  113. package/dist/services/schemas/base.entity-names.schemas.d.ts.map +1 -1
  114. package/dist/services/schemas/base.entity-names.schemas.js +1 -1
  115. package/dist/services/schemas/base.entity-names.schemas.js.map +1 -1
  116. package/dist/services/schemas/base.metadata.schemas.d.ts +1 -1
  117. package/dist/services/schemas/base.metadata.schemas.d.ts.map +1 -1
  118. package/dist/services/schemas/base.metadata.schemas.js +1 -1
  119. package/dist/services/schemas/base.metadata.schemas.js.map +1 -1
  120. package/dist/services/schemas/base.pagination.schemas.d.ts +1 -1
  121. package/dist/services/schemas/base.pagination.schemas.d.ts.map +1 -1
  122. package/dist/services/schemas/base.pagination.schemas.js +1 -1
  123. package/dist/services/schemas/base.pagination.schemas.js.map +1 -1
  124. package/dist/services/schemas/base.primitives.schemas.d.ts +3 -1
  125. package/dist/services/schemas/base.primitives.schemas.d.ts.map +1 -1
  126. package/dist/services/schemas/base.primitives.schemas.js +8 -7
  127. package/dist/services/schemas/base.primitives.schemas.js.map +1 -1
  128. package/dist/services/schemas/index.d.ts +5 -5
  129. package/dist/services/schemas/index.d.ts.map +1 -1
  130. package/dist/services/schemas/index.js +5 -5
  131. package/dist/services/schemas/index.js.map +1 -1
  132. package/dist/services/tag.d.ts +1 -1
  133. package/dist/services/tag.d.ts.map +1 -1
  134. package/dist/services/tag.js +2 -2
  135. package/dist/services/tag.js.map +1 -1
  136. package/dist/services/tag.schemas.d.ts +13 -13
  137. package/dist/services/tag.schemas.d.ts.map +1 -1
  138. package/dist/services/tag.schemas.js +50 -50
  139. package/dist/services/tag.schemas.js.map +1 -1
  140. package/dist/services/track.d.ts +128 -4
  141. package/dist/services/track.d.ts.map +1 -1
  142. package/dist/services/track.js +79 -10
  143. package/dist/services/track.js.map +1 -1
  144. package/dist/services/track.schemas.d.ts +213 -25
  145. package/dist/services/track.schemas.d.ts.map +1 -1
  146. package/dist/services/track.schemas.js +206 -57
  147. package/dist/services/track.schemas.js.map +1 -1
  148. package/dist/services/track.utils.d.ts +16 -7
  149. package/dist/services/track.utils.d.ts.map +1 -1
  150. package/dist/services/track.utils.js +49 -48
  151. package/dist/services/track.utils.js.map +1 -1
  152. package/dist/services/user.d.ts +19 -1
  153. package/dist/services/user.d.ts.map +1 -1
  154. package/dist/services/user.js +3 -2
  155. package/dist/services/user.js.map +1 -1
  156. package/dist/services/user.schemas.d.ts +321 -63
  157. package/dist/services/user.schemas.d.ts.map +1 -1
  158. package/dist/services/user.schemas.js +197 -88
  159. package/dist/services/user.schemas.js.map +1 -1
  160. package/dist/utils.d.ts +37 -2
  161. package/dist/utils.d.ts.map +1 -1
  162. package/dist/utils.js +105 -20
  163. package/dist/utils.js.map +1 -1
  164. package/package.json +167 -154
  165. package/dist/__tests__/utils.test.d.ts +0 -2
  166. package/dist/__tests__/utils.test.d.ts.map +0 -1
  167. package/dist/__tests__/utils.test.js +0 -86
  168. package/dist/__tests__/utils.test.js.map +0 -1
package/dist/utils.js CHANGED
@@ -33,8 +33,8 @@ export async function parseLastFmResponse(response) {
33
33
  if (!response.ok) {
34
34
  throw new LastFmApiError(`HTTP Error: ${httpStatus} ${response.statusText}`, httpStatus, typeof body?.error === 'number' ? body.error : undefined);
35
35
  }
36
- if (body && body.error) {
37
- const code = typeof body.error === 'number' ? body.error : undefined;
36
+ if (body?.error) {
37
+ const code = typeof body?.error === 'number' ? body.error : undefined;
38
38
  throw new LastFmApiError(`Last.fm API Error ${body.error}: ${body.message ?? ''}`.trim(), httpStatus, code);
39
39
  }
40
40
  return body;
@@ -55,7 +55,7 @@ export function buildUrl(config, method, params = {}) {
55
55
  method,
56
56
  api_key: config.apiKey,
57
57
  format: 'json',
58
- ...cleanParams(params)
58
+ ...cleanParams(params),
59
59
  });
60
60
  return `${baseUrl}?${urlParams.toString()}`;
61
61
  }
@@ -91,35 +91,120 @@ export function buildAuthUrl(config, method, params = {}) {
91
91
  const authParams = {
92
92
  method,
93
93
  api_key: config.apiKey,
94
- ...cleanParams(params)
94
+ ...cleanParams(params),
95
95
  };
96
96
  const signature = generateSignature(config, authParams);
97
97
  const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
98
98
  const urlParams = new URLSearchParams({
99
99
  ...authParams,
100
100
  api_sig: signature,
101
- format: 'json'
101
+ format: 'json',
102
102
  });
103
103
  return `${baseUrl}?${urlParams.toString()}`;
104
104
  }
105
+ // ─────────────────────────────────────────────────────────────────────────────
106
+ // Signed POST transport (issue #68)
107
+ //
108
+ // One reusable signed POST path used by every authenticated write. Services are
109
+ // responsible only for the domain-specific param shape (e.g. indexed keys for
110
+ // batch scrobble). Everything else — session resolution, signature, body
111
+ // encoding, error routing — lives here.
112
+ //
113
+ // Internal on purpose. Do not re-export through the public `exports` map of
114
+ // `package.json`. The issue explicitly requires that this helper is not
115
+ // promoted to a public API of the package.
116
+ // ─────────────────────────────────────────────────────────────────────────────
117
+ /** Last.fm wire fields that the transport always owns. */
118
+ const RESERVED_FIELDS = ['method', 'api_key', 'api_sig', 'format'];
105
119
  /**
106
- * Realiza una petición POST con body URL-encoded
120
+ * Send a signed POST to the Last.fm API and return the parsed JSON body.
121
+ *
122
+ * Behaviour:
123
+ *
124
+ * - Reserved fields (`method`, `api_key`, `api_sig`, `format`) are always
125
+ * generated internally; any caller-supplied values are silently ignored.
126
+ * - Signature input is the sorted concatenation of `method`, `api_key`,
127
+ * functional params, and `sk` (when required). `format` and `api_sig`
128
+ * are never part of the signature input.
129
+ * - The body is `application/x-www-form-urlencoded` and contains `method`,
130
+ * `api_key`, every functional param, optional `sk`, `api_sig`, and
131
+ * `format=json`. Nothing goes in the URL.
132
+ * - Missing `sharedSecret` or required `sk` fail with a sanitized
133
+ * `LastFmApiError` (no request values in the message) before any
134
+ * `fetch` is issued.
135
+ * - The response is routed through `parseLastFmResponse`, so HTTP
136
+ * failures and Last.fm error envelopes both surface as `LastFmApiError`.
137
+ * An empty or non-JSON success body is returned as-is, not as an error.
107
138
  */
108
- export async function postFetcher(url, body) {
109
- const response = await fetch(url, {
110
- method: 'POST',
111
- headers: {
112
- 'Content-Type': 'application/x-www-form-urlencoded'
113
- },
114
- body
115
- });
116
- if (!response.ok) {
117
- throw new Error(`HTTP Error: ${response.status} ${response.statusText}`);
139
+ export async function signedPost(config, method, options) {
140
+ const requiresSession = options.requiresSession ?? true;
141
+ // 1. Shared secret must exist before we touch anything.
142
+ if (!config.sharedSecret) {
143
+ throw new LastFmApiError('A `sharedSecret` is required for signed methods. Pass `sharedSecret` in the LastFmConfig.', 0);
118
144
  }
119
- const data = await response.json();
120
- if (data.error) {
121
- throw new Error(`Last.fm API Error ${data.error}: ${data.message}`);
145
+ // 2. Coerce params to string and drop undefined/null.
146
+ const cleanParams = {};
147
+ for (const [k, v] of Object.entries(options.params)) {
148
+ if (v !== undefined && v !== null) {
149
+ cleanParams[k] = String(v);
150
+ }
122
151
  }
123
- return data;
152
+ // 3. Resolve `sk` for session-required methods.
153
+ if (requiresSession) {
154
+ const requestSk = cleanParams.sk;
155
+ const resolvedSk = requestSk ?? config.sessionKey;
156
+ if (!resolvedSk) {
157
+ throw new LastFmApiError('A session key (`sk`) is required for this method. Pass `sk` in the request or set `sessionKey` on the LastFmConfig.', 0);
158
+ }
159
+ cleanParams.sk = resolvedSk;
160
+ }
161
+ // 4. Drop any reserved field the caller tried to inject. The transport
162
+ // owns these — they will be set to canonical values below.
163
+ for (const reserved of RESERVED_FIELDS) {
164
+ delete cleanParams[reserved];
165
+ }
166
+ // 5. Build signature input. Note: `format` and `api_sig` are never part
167
+ // of the signature input per the Last.fm contract.
168
+ const sigInput = {
169
+ method,
170
+ api_key: config.apiKey,
171
+ ...cleanParams,
172
+ };
173
+ const sigString = Object.keys(sigInput)
174
+ .sort()
175
+ .map((k) => `${k}${sigInput[k]}`)
176
+ .join('');
177
+ const api_sig = md5(sigString + config.sharedSecret);
178
+ // 6. Build body. Order: method, api_key, functional params (incl. sk if
179
+ // present), api_sig, format=json. URLSearchParams handles encoding.
180
+ const body = new URLSearchParams();
181
+ body.set('method', method);
182
+ body.set('api_key', config.apiKey);
183
+ for (const [k, v] of Object.entries(cleanParams)) {
184
+ body.set(k, v);
185
+ }
186
+ body.set('api_sig', api_sig);
187
+ body.set('format', 'json');
188
+ // 7. Merge caller `init` safely. The transport owns method, body, and
189
+ // Content-Type; signal and other safe headers pass through. Caller
190
+ // headers go first so the canonical Content-Type always wins.
191
+ const callerHeaders = (options.init?.headers ?? {});
192
+ const finalHeaders = {
193
+ ...callerHeaders,
194
+ 'Content-Type': 'application/x-www-form-urlencoded',
195
+ };
196
+ const finalInit = {
197
+ ...options.init,
198
+ method: 'POST',
199
+ headers: finalHeaders,
200
+ body: body.toString(),
201
+ };
202
+ if (options.init?.signal) {
203
+ finalInit.signal = options.init.signal;
204
+ }
205
+ // 8. Send.
206
+ const baseUrl = config.baseUrl ?? DEFAULT_BASE_URL;
207
+ const response = await fetch(baseUrl, finalInit);
208
+ return (await parseLastFmResponse(response));
124
209
  }
125
210
  //# sourceMappingURL=utils.js.map
package/dist/utils.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,156 +1,169 @@
1
1
  {
2
- "name": "@ansango/lastfm-api",
3
- "version": "3.1.3",
4
- "description": "A universal Last.fm API client for Node.js and Browser",
5
- "type": "module",
6
- "main": "./dist/index.js",
7
- "types": "./dist/index.d.ts",
8
- "exports": {
9
- ".": {
10
- "import": "./dist/index.js",
11
- "types": "./dist/index.d.ts"
12
- },
13
- "./user": {
14
- "import": "./dist/entrypoints/user.js",
15
- "types": "./dist/entrypoints/user.d.ts"
16
- },
17
- "./user/schemas": {
18
- "import": "./dist/entrypoints/user.schemas.js",
19
- "types": "./dist/entrypoints/user.schemas.d.ts"
20
- },
21
- "./album": {
22
- "import": "./dist/entrypoints/album.js",
23
- "types": "./dist/entrypoints/album.d.ts"
24
- },
25
- "./album/schemas": {
26
- "import": "./dist/entrypoints/album.schemas.js",
27
- "types": "./dist/entrypoints/album.schemas.d.ts"
28
- },
29
- "./artist": {
30
- "import": "./dist/entrypoints/artist.js",
31
- "types": "./dist/entrypoints/artist.d.ts"
32
- },
33
- "./artist/schemas": {
34
- "import": "./dist/entrypoints/artist.schemas.js",
35
- "types": "./dist/entrypoints/artist.schemas.d.ts"
36
- },
37
- "./track": {
38
- "import": "./dist/entrypoints/track.js",
39
- "types": "./dist/entrypoints/track.d.ts"
40
- },
41
- "./track/schemas": {
42
- "import": "./dist/entrypoints/track.schemas.js",
43
- "types": "./dist/entrypoints/track.schemas.d.ts"
44
- },
45
- "./tag": {
46
- "import": "./dist/entrypoints/tag.js",
47
- "types": "./dist/entrypoints/tag.d.ts"
48
- },
49
- "./tag/schemas": {
50
- "import": "./dist/entrypoints/tag.schemas.js",
51
- "types": "./dist/entrypoints/tag.schemas.d.ts"
52
- },
53
- "./chart": {
54
- "import": "./dist/entrypoints/chart.js",
55
- "types": "./dist/entrypoints/chart.d.ts"
56
- },
57
- "./chart/schemas": {
58
- "import": "./dist/entrypoints/chart.schemas.js",
59
- "types": "./dist/entrypoints/chart.schemas.d.ts"
60
- },
61
- "./geo": {
62
- "import": "./dist/entrypoints/geo.js",
63
- "types": "./dist/entrypoints/geo.d.ts"
64
- },
65
- "./geo/schemas": {
66
- "import": "./dist/entrypoints/geo.schemas.js",
67
- "types": "./dist/entrypoints/geo.schemas.d.ts"
68
- },
69
- "./library": {
70
- "import": "./dist/entrypoints/library.js",
71
- "types": "./dist/entrypoints/library.d.ts"
72
- },
73
- "./library/schemas": {
74
- "import": "./dist/entrypoints/library.schemas.js",
75
- "types": "./dist/entrypoints/library.schemas.d.ts"
76
- },
77
- "./auth": {
78
- "import": "./dist/entrypoints/auth.js",
79
- "types": "./dist/entrypoints/auth.d.ts"
80
- },
81
- "./auth/schemas": {
82
- "import": "./dist/entrypoints/auth.schemas.js",
83
- "types": "./dist/entrypoints/auth.schemas.d.ts"
84
- },
85
- "./schemas": {
86
- "import": "./dist/entrypoints/base.schemas.js",
87
- "types": "./dist/entrypoints/base.schemas.d.ts"
88
- }
89
- },
90
- "files": [
91
- "dist",
92
- "README.md",
93
- "LICENSE",
94
- "CHANGELOG.md"
95
- ],
96
- "engines": {
97
- "node": ">=20.0.0"
98
- },
99
- "scripts": {
100
- "build": "rimraf dist && tsc",
101
- "clean": "rimraf dist",
102
- "dev": "bun run clean && tsc --watch --project tsconfig.dev.json",
103
- "test": "bun test-real.ts",
104
- "prepublishOnly": "bun run build",
105
- "changelog": "bun scripts/changelog.ts",
106
- "release": "bun scripts/release.ts",
107
- "release:patch": "bun scripts/release.ts patch",
108
- "release:minor": "bun scripts/release.ts minor",
109
- "release:major": "bun scripts/release.ts major",
110
- "release:alpha": "bun scripts/release.ts alpha",
111
- "release:beta": "bun scripts/release.ts beta",
112
- "gh:release": "bun scripts/github-release.ts"
113
- },
114
- "repository": {
115
- "type": "git",
116
- "url": "git+https://github.com/ansango/lastfm-api.git"
117
- },
118
- "homepage": "https://github.com/ansango/lastfm-api#readme",
119
- "bugs": {
120
- "url": "https://github.com/ansango/lastfm-api/issues"
121
- },
122
- "publishConfig": {
123
- "access": "public"
124
- },
125
- "author": "Anibal Santos",
126
- "license": "MIT",
127
- "keywords": [
128
- "client",
129
- "last-fm",
130
- "lastfm",
131
- "nodejs",
132
- "api",
133
- "node",
134
- "typescript",
135
- "browser",
136
- "universal",
137
- "esm",
138
- "zod",
139
- "validation"
140
- ],
141
- "dependencies": {
142
- "js-md5": "^0.8.3",
143
- "zod": "4.1.12"
144
- },
145
- "devDependencies": {
146
- "@types/node": "^24.10.0",
147
- "dotenv": "^17.2.3",
148
- "rimraf": "^6.1.0",
149
- "typescript": "^5.9.3"
150
- },
151
- "config": {
152
- "commitizen": {
153
- "path": "./node_modules/cz-conventional-changelog"
154
- }
155
- }
2
+ "name": "@ansango/lastfm-api",
3
+ "version": "3.2.0",
4
+ "description": "A universal Last.fm API client for Node.js and Browser",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "import": "./dist/index.js",
11
+ "types": "./dist/index.d.ts"
12
+ },
13
+ "./user": {
14
+ "import": "./dist/entrypoints/user.js",
15
+ "types": "./dist/entrypoints/user.d.ts"
16
+ },
17
+ "./user/schemas": {
18
+ "import": "./dist/entrypoints/user.schemas.js",
19
+ "types": "./dist/entrypoints/user.schemas.d.ts"
20
+ },
21
+ "./album": {
22
+ "import": "./dist/entrypoints/album.js",
23
+ "types": "./dist/entrypoints/album.d.ts"
24
+ },
25
+ "./album/schemas": {
26
+ "import": "./dist/entrypoints/album.schemas.js",
27
+ "types": "./dist/entrypoints/album.schemas.d.ts"
28
+ },
29
+ "./artist": {
30
+ "import": "./dist/entrypoints/artist.js",
31
+ "types": "./dist/entrypoints/artist.d.ts"
32
+ },
33
+ "./artist/schemas": {
34
+ "import": "./dist/entrypoints/artist.schemas.js",
35
+ "types": "./dist/entrypoints/artist.schemas.d.ts"
36
+ },
37
+ "./track": {
38
+ "import": "./dist/entrypoints/track.js",
39
+ "types": "./dist/entrypoints/track.d.ts"
40
+ },
41
+ "./track/schemas": {
42
+ "import": "./dist/entrypoints/track.schemas.js",
43
+ "types": "./dist/entrypoints/track.schemas.d.ts"
44
+ },
45
+ "./tag": {
46
+ "import": "./dist/entrypoints/tag.js",
47
+ "types": "./dist/entrypoints/tag.d.ts"
48
+ },
49
+ "./tag/schemas": {
50
+ "import": "./dist/entrypoints/tag.schemas.js",
51
+ "types": "./dist/entrypoints/tag.schemas.d.ts"
52
+ },
53
+ "./chart": {
54
+ "import": "./dist/entrypoints/chart.js",
55
+ "types": "./dist/entrypoints/chart.d.ts"
56
+ },
57
+ "./chart/schemas": {
58
+ "import": "./dist/entrypoints/chart.schemas.js",
59
+ "types": "./dist/entrypoints/chart.schemas.d.ts"
60
+ },
61
+ "./geo": {
62
+ "import": "./dist/entrypoints/geo.js",
63
+ "types": "./dist/entrypoints/geo.d.ts"
64
+ },
65
+ "./geo/schemas": {
66
+ "import": "./dist/entrypoints/geo.schemas.js",
67
+ "types": "./dist/entrypoints/geo.schemas.d.ts"
68
+ },
69
+ "./library": {
70
+ "import": "./dist/entrypoints/library.js",
71
+ "types": "./dist/entrypoints/library.d.ts"
72
+ },
73
+ "./library/schemas": {
74
+ "import": "./dist/entrypoints/library.schemas.js",
75
+ "types": "./dist/entrypoints/library.schemas.d.ts"
76
+ },
77
+ "./auth": {
78
+ "import": "./dist/entrypoints/auth.js",
79
+ "types": "./dist/entrypoints/auth.d.ts"
80
+ },
81
+ "./auth/schemas": {
82
+ "import": "./dist/entrypoints/auth.schemas.js",
83
+ "types": "./dist/entrypoints/auth.schemas.d.ts"
84
+ },
85
+ "./schemas": {
86
+ "import": "./dist/entrypoints/base.schemas.js",
87
+ "types": "./dist/entrypoints/base.schemas.d.ts"
88
+ }
89
+ },
90
+ "files": [
91
+ "dist",
92
+ "README.md",
93
+ "LICENSE",
94
+ "CHANGELOG.md"
95
+ ],
96
+ "engines": {
97
+ "node": ">=20.0.0"
98
+ },
99
+ "scripts": {
100
+ "build": "rimraf dist && tsc",
101
+ "clean": "rimraf dist",
102
+ "dev": "bun run clean && tsc --watch --project tsconfig.dev.json",
103
+ "typecheck": "tsc --noEmit -p tsconfig.test.json",
104
+ "test": "bun run test:unit",
105
+ "test:unit": "bun test src/__tests__",
106
+ "test:integration:live": "bun test-real.ts",
107
+ "lint": "biome check .",
108
+ "lint:fix": "biome check --write .",
109
+ "format": "biome format --write .",
110
+ "format:check": "biome format .",
111
+ "prepublishOnly": "bun run build",
112
+ "changelog": "bun scripts/changelog.ts",
113
+ "release": "bun scripts/release.ts",
114
+ "release:patch": "bun scripts/release.ts patch",
115
+ "release:minor": "bun scripts/release.ts minor",
116
+ "release:major": "bun scripts/release.ts major",
117
+ "release:alpha": "bun scripts/release.ts alpha",
118
+ "release:beta": "bun scripts/release.ts beta",
119
+ "gh:release": "bun scripts/github-release.ts",
120
+ "tool:dev": "bun install --cwd tool/api-scalar && bun run --cwd tool/api-scalar dev",
121
+ "tool:start": "bun install --cwd tool/api-scalar && bun run --cwd tool/api-scalar start",
122
+ "tool:test": "bun install --cwd tool/api-scalar && bun run --cwd tool/api-scalar test",
123
+ "tool:typecheck": "bun install --cwd tool/api-scalar && bun run --cwd tool/api-scalar typecheck"
124
+ },
125
+ "repository": {
126
+ "type": "git",
127
+ "url": "git+https://github.com/ansango/lastfm-api.git"
128
+ },
129
+ "homepage": "https://github.com/ansango/lastfm-api#readme",
130
+ "bugs": {
131
+ "url": "https://github.com/ansango/lastfm-api/issues"
132
+ },
133
+ "publishConfig": {
134
+ "access": "public"
135
+ },
136
+ "author": "Anibal Santos",
137
+ "license": "MIT",
138
+ "keywords": [
139
+ "client",
140
+ "last-fm",
141
+ "lastfm",
142
+ "nodejs",
143
+ "api",
144
+ "node",
145
+ "typescript",
146
+ "browser",
147
+ "universal",
148
+ "esm",
149
+ "zod",
150
+ "validation"
151
+ ],
152
+ "dependencies": {
153
+ "js-md5": "^0.8.3",
154
+ "zod": "4.1.12"
155
+ },
156
+ "devDependencies": {
157
+ "@biomejs/biome": "^2.5.11",
158
+ "@types/bun": "^1.4.0",
159
+ "@types/node": "^24.10.0",
160
+ "dotenv": "^17.2.3",
161
+ "rimraf": "^6.1.0",
162
+ "typescript": "^5.9.3"
163
+ },
164
+ "config": {
165
+ "commitizen": {
166
+ "path": "./node_modules/cz-conventional-changelog"
167
+ }
168
+ }
156
169
  }
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=utils.test.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.test.d.ts","sourceRoot":"","sources":["../../src/__tests__/utils.test.ts"],"names":[],"mappings":""}
@@ -1,86 +0,0 @@
1
- import { test, beforeEach, afterEach, describe } from 'node:test';
2
- import assert from 'node:assert/strict';
3
- import { LastFmClient } from '../client.js';
4
- import { buildUrl, buildAuthUrl } from '../utils.js';
5
- /**
6
- * Regression tests for issue #58:
7
- * `new LastFmClient({ apiKey })` must not throw "Failed to parse URL from
8
- * undefined" because `buildUrl` / `buildAuthUrl` default `baseUrl`.
9
- */
10
- /** Minimal fake artist payload that satisfies the Zod schema. */
11
- const fakeArtistPayload = {
12
- artist: {
13
- name: 'Radiohead',
14
- mbid: 'a74b1b7f-71a5-4011-9441-d0b5e4122711',
15
- url: 'https://www.last.fm/music/Radiohead',
16
- image: [],
17
- streamable: '0',
18
- ontour: '0',
19
- stats: {
20
- listeners: '1',
21
- playcount: '1',
22
- userplaycount: '0'
23
- },
24
- similar: { artist: [] },
25
- tags: { tag: [] },
26
- bio: {
27
- published: '2024-01-01',
28
- summary: 'Test',
29
- content: 'Test'
30
- }
31
- }
32
- };
33
- describe('issue #58: default baseUrl', () => {
34
- const originalFetch = globalThis.fetch;
35
- beforeEach(() => {
36
- // Mock fetch so the test does not require a real API key.
37
- globalThis.fetch = (async (input) => {
38
- const url = typeof input === 'string' ? input : input.toString();
39
- // Sanity: a syntactically valid URL must be passed to fetch.
40
- // Before the fix this would throw "Failed to parse URL from undefined".
41
- new URL(url);
42
- return new Response(JSON.stringify(fakeArtistPayload), {
43
- status: 200,
44
- headers: { 'Content-Type': 'application/json' }
45
- });
46
- });
47
- });
48
- afterEach(() => {
49
- globalThis.fetch = originalFetch;
50
- });
51
- test('LastFmClient constructed without baseUrl + getInfo does not throw "Failed to parse URL from undefined"', async () => {
52
- const client = new LastFmClient({ apiKey: 'test' });
53
- const result = await client.artist.getInfo({ artist: 'Radiohead' });
54
- assert.equal(result.artist.name, 'Radiohead');
55
- });
56
- test('buildUrl defaults baseUrl when config.baseUrl is undefined', () => {
57
- const config = { apiKey: 'test' };
58
- const url = buildUrl(config, 'artist.getInfo', { artist: 'Radiohead' });
59
- assert.match(url, /^https:\/\/ws\.audioscrobbler\.com\/2\.0\/\?/);
60
- assert.match(url, /method=artist\.getInfo/);
61
- assert.match(url, /api_key=test/);
62
- // Must not produce the literal "undefined?..." string that caused the original bug.
63
- assert.doesNotMatch(url, /^undefined/);
64
- });
65
- test('buildAuthUrl defaults baseUrl when config.baseUrl is undefined', () => {
66
- const config = { apiKey: 'test', sharedSecret: 'secret' };
67
- const url = buildAuthUrl(config, 'track.scrobble', {
68
- artist: 'Radiohead',
69
- track: 'OK Computer',
70
- timestamp: 1,
71
- sk: 'session'
72
- });
73
- assert.match(url, /^https:\/\/ws\.audioscrobbler\.com\/2\.0\/\?/);
74
- assert.match(url, /api_sig=[a-f0-9]{32}/);
75
- assert.doesNotMatch(url, /^undefined/);
76
- });
77
- test('buildUrl honours an explicit baseUrl when provided', () => {
78
- const config = {
79
- apiKey: 'test',
80
- baseUrl: 'https://example.test/api/'
81
- };
82
- const url = buildUrl(config, 'artist.getInfo', { artist: 'X' });
83
- assert.match(url, /^https:\/\/example\.test\/api\/\?/);
84
- });
85
- });
86
- //# sourceMappingURL=utils.test.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"utils.test.js","sourceRoot":"","sources":["../../src/__tests__/utils.test.ts"],"names":[],"mappings":"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"}