@tidal-music/api 0.1.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/dist/index.js ADDED
@@ -0,0 +1,321 @@
1
+ const k = /\{[^{}]+\}/g;
2
+ class v extends Request {
3
+ constructor(t, e) {
4
+ super(t, e);
5
+ for (const n in e)
6
+ n in this || (this[n] = e[n]);
7
+ }
8
+ }
9
+ function L() {
10
+ return Math.random().toString(36).slice(2, 11);
11
+ }
12
+ function B(r) {
13
+ let {
14
+ baseUrl: t = "",
15
+ fetch: e = globalThis.fetch,
16
+ querySerializer: n,
17
+ bodySerializer: i,
18
+ headers: s,
19
+ ...o
20
+ } = { ...r };
21
+ t = E(t);
22
+ const l = [];
23
+ async function u(f, a) {
24
+ const {
25
+ baseUrl: h,
26
+ fetch: x = e,
27
+ headers: H,
28
+ params: m = {},
29
+ parseAs: p = "json",
30
+ querySerializer: b,
31
+ bodySerializer: T = i ?? N,
32
+ body: q,
33
+ ...I
34
+ } = a || {};
35
+ h && (t = E(h));
36
+ let j = typeof n == "function" ? n : C(n);
37
+ b && (j = typeof b == "function" ? b : C({
38
+ ...typeof n == "object" ? n : {},
39
+ ...b
40
+ }));
41
+ const g = q === void 0 ? void 0 : T(q), D = (
42
+ // with no body, we should not to set Content-Type
43
+ g === void 0 || // if serialized body is FormData; browser will correctly set Content-Type & boundary expression
44
+ g instanceof FormData ? {} : {
45
+ "Content-Type": "application/json"
46
+ }
47
+ ), P = {
48
+ redirect: "follow",
49
+ ...o,
50
+ ...I,
51
+ body: g,
52
+ headers: M(D, s, H, m.header)
53
+ };
54
+ let $, S, R = new v(W(f, { baseUrl: t, params: m, querySerializer: j }), P);
55
+ if (l.length) {
56
+ $ = L(), S = Object.freeze({
57
+ baseUrl: t,
58
+ fetch: x,
59
+ parseAs: p,
60
+ querySerializer: j,
61
+ bodySerializer: T
62
+ });
63
+ for (const d of l)
64
+ if (d && typeof d == "object" && typeof d.onRequest == "function") {
65
+ const y = await d.onRequest({
66
+ request: R,
67
+ schemaPath: f,
68
+ params: m,
69
+ options: S,
70
+ id: $
71
+ });
72
+ if (y) {
73
+ if (!(y instanceof Request))
74
+ throw new Error("onRequest: must return new Request() when modifying the request");
75
+ R = y;
76
+ }
77
+ }
78
+ }
79
+ let c = await x(R);
80
+ if (l.length)
81
+ for (let d = l.length - 1; d >= 0; d--) {
82
+ const y = l[d];
83
+ if (y && typeof y == "object" && typeof y.onResponse == "function") {
84
+ const z = await y.onResponse({
85
+ request: R,
86
+ response: c,
87
+ schemaPath: f,
88
+ params: m,
89
+ options: S,
90
+ id: $
91
+ });
92
+ if (z) {
93
+ if (!(z instanceof Response))
94
+ throw new Error("onResponse: must return new Response() when modifying the response");
95
+ c = z;
96
+ }
97
+ }
98
+ }
99
+ if (c.status === 204 || c.headers.get("Content-Length") === "0")
100
+ return c.ok ? { data: {}, response: c } : { error: {}, response: c };
101
+ if (c.ok)
102
+ return p === "stream" ? { data: c.body, response: c } : { data: await c[p](), response: c };
103
+ let A = await c.text();
104
+ try {
105
+ A = JSON.parse(A);
106
+ } catch {
107
+ }
108
+ return { error: A, response: c };
109
+ }
110
+ return {
111
+ /** Call a GET endpoint */
112
+ GET(f, a) {
113
+ return u(f, { ...a, method: "GET" });
114
+ },
115
+ /** Call a PUT endpoint */
116
+ PUT(f, a) {
117
+ return u(f, { ...a, method: "PUT" });
118
+ },
119
+ /** Call a POST endpoint */
120
+ POST(f, a) {
121
+ return u(f, { ...a, method: "POST" });
122
+ },
123
+ /** Call a DELETE endpoint */
124
+ DELETE(f, a) {
125
+ return u(f, { ...a, method: "DELETE" });
126
+ },
127
+ /** Call a OPTIONS endpoint */
128
+ OPTIONS(f, a) {
129
+ return u(f, { ...a, method: "OPTIONS" });
130
+ },
131
+ /** Call a HEAD endpoint */
132
+ HEAD(f, a) {
133
+ return u(f, { ...a, method: "HEAD" });
134
+ },
135
+ /** Call a PATCH endpoint */
136
+ PATCH(f, a) {
137
+ return u(f, { ...a, method: "PATCH" });
138
+ },
139
+ /** Call a TRACE endpoint */
140
+ TRACE(f, a) {
141
+ return u(f, { ...a, method: "TRACE" });
142
+ },
143
+ /** Register middleware */
144
+ use(...f) {
145
+ for (const a of f)
146
+ if (a) {
147
+ if (typeof a != "object" || !("onRequest" in a || "onResponse" in a))
148
+ throw new Error("Middleware must be an object with one of `onRequest()` or `onResponse()`");
149
+ l.push(a);
150
+ }
151
+ },
152
+ /** Unregister middleware */
153
+ eject(...f) {
154
+ for (const a of f) {
155
+ const h = l.indexOf(a);
156
+ h !== -1 && l.splice(h, 1);
157
+ }
158
+ }
159
+ };
160
+ }
161
+ function w(r, t, e) {
162
+ if (t == null)
163
+ return "";
164
+ if (typeof t == "object")
165
+ throw new Error(
166
+ "Deeply-nested arrays/objects aren’t supported. Provide your own `querySerializer()` to handle these."
167
+ );
168
+ return `${r}=${(e == null ? void 0 : e.allowReserved) === !0 ? t : encodeURIComponent(t)}`;
169
+ }
170
+ function O(r, t, e) {
171
+ if (!t || typeof t != "object")
172
+ return "";
173
+ const n = [], i = {
174
+ simple: ",",
175
+ label: ".",
176
+ matrix: ";"
177
+ }[e.style] || "&";
178
+ if (e.style !== "deepObject" && e.explode === !1) {
179
+ for (const l in t)
180
+ n.push(l, e.allowReserved === !0 ? t[l] : encodeURIComponent(t[l]));
181
+ const o = n.join(",");
182
+ switch (e.style) {
183
+ case "form":
184
+ return `${r}=${o}`;
185
+ case "label":
186
+ return `.${o}`;
187
+ case "matrix":
188
+ return `;${r}=${o}`;
189
+ default:
190
+ return o;
191
+ }
192
+ }
193
+ for (const o in t) {
194
+ const l = e.style === "deepObject" ? `${r}[${o}]` : o;
195
+ n.push(w(l, t[o], e));
196
+ }
197
+ const s = n.join(i);
198
+ return e.style === "label" || e.style === "matrix" ? `${i}${s}` : s;
199
+ }
200
+ function U(r, t, e) {
201
+ if (!Array.isArray(t))
202
+ return "";
203
+ if (e.explode === !1) {
204
+ const s = { form: ",", spaceDelimited: "%20", pipeDelimited: "|" }[e.style] || ",", o = (e.allowReserved === !0 ? t : t.map((l) => encodeURIComponent(l))).join(s);
205
+ switch (e.style) {
206
+ case "simple":
207
+ return o;
208
+ case "label":
209
+ return `.${o}`;
210
+ case "matrix":
211
+ return `;${r}=${o}`;
212
+ default:
213
+ return `${r}=${o}`;
214
+ }
215
+ }
216
+ const n = { simple: ",", label: ".", matrix: ";" }[e.style] || "&", i = [];
217
+ for (const s of t)
218
+ e.style === "simple" || e.style === "label" ? i.push(e.allowReserved === !0 ? s : encodeURIComponent(s)) : i.push(w(r, s, e));
219
+ return e.style === "label" || e.style === "matrix" ? `${n}${i.join(n)}` : i.join(n);
220
+ }
221
+ function C(r) {
222
+ return function(e) {
223
+ const n = [];
224
+ if (e && typeof e == "object")
225
+ for (const i in e) {
226
+ const s = e[i];
227
+ if (s != null) {
228
+ if (Array.isArray(s)) {
229
+ n.push(
230
+ U(i, s, {
231
+ style: "form",
232
+ explode: !0,
233
+ ...r == null ? void 0 : r.array,
234
+ allowReserved: (r == null ? void 0 : r.allowReserved) || !1
235
+ })
236
+ );
237
+ continue;
238
+ }
239
+ if (typeof s == "object") {
240
+ n.push(
241
+ O(i, s, {
242
+ style: "deepObject",
243
+ explode: !0,
244
+ ...r == null ? void 0 : r.object,
245
+ allowReserved: (r == null ? void 0 : r.allowReserved) || !1
246
+ })
247
+ );
248
+ continue;
249
+ }
250
+ n.push(w(i, s, r));
251
+ }
252
+ }
253
+ return n.join("&");
254
+ };
255
+ }
256
+ function F(r, t) {
257
+ let e = r;
258
+ for (const n of r.match(k) ?? []) {
259
+ let i = n.substring(1, n.length - 1), s = !1, o = "simple";
260
+ if (i.endsWith("*") && (s = !0, i = i.substring(0, i.length - 1)), i.startsWith(".") ? (o = "label", i = i.substring(1)) : i.startsWith(";") && (o = "matrix", i = i.substring(1)), !t || t[i] === void 0 || t[i] === null)
261
+ continue;
262
+ const l = t[i];
263
+ if (Array.isArray(l)) {
264
+ e = e.replace(n, U(i, l, { style: o, explode: s }));
265
+ continue;
266
+ }
267
+ if (typeof l == "object") {
268
+ e = e.replace(n, O(i, l, { style: o, explode: s }));
269
+ continue;
270
+ }
271
+ if (o === "matrix") {
272
+ e = e.replace(n, `;${w(i, l)}`);
273
+ continue;
274
+ }
275
+ e = e.replace(n, o === "label" ? `.${encodeURIComponent(l)}` : encodeURIComponent(l));
276
+ }
277
+ return e;
278
+ }
279
+ function N(r) {
280
+ return r instanceof FormData ? r : JSON.stringify(r);
281
+ }
282
+ function W(r, t) {
283
+ var i;
284
+ let e = `${t.baseUrl}${r}`;
285
+ (i = t.params) != null && i.path && (e = F(e, t.params.path));
286
+ let n = t.querySerializer(t.params.query ?? {});
287
+ return n.startsWith("?") && (n = n.substring(1)), n && (e += `?${n}`), e;
288
+ }
289
+ function M(...r) {
290
+ const t = new Headers();
291
+ for (const e of r) {
292
+ if (!e || typeof e != "object")
293
+ continue;
294
+ const n = e instanceof Headers ? e.entries() : Object.entries(e);
295
+ for (const [i, s] of n)
296
+ if (s === null)
297
+ t.delete(i);
298
+ else if (Array.isArray(s))
299
+ for (const o of s)
300
+ t.append(i, o);
301
+ else s !== void 0 && t.set(i, s);
302
+ }
303
+ return t;
304
+ }
305
+ function E(r) {
306
+ return r.endsWith("/") ? r.substring(0, r.length - 1) : r;
307
+ }
308
+ function Q(r) {
309
+ const t = {
310
+ async onRequest({ request: n }) {
311
+ const i = await r.getCredentials();
312
+ return n.headers.set("Authorization", `Bearer ${i.token}`), n;
313
+ }
314
+ }, e = B({
315
+ baseUrl: "https://openapi.tidal.com/v2/"
316
+ });
317
+ return e.use(t), e;
318
+ }
319
+ export {
320
+ Q as createAPIClient
321
+ };
package/package.json ADDED
@@ -0,0 +1,49 @@
1
+ {
2
+ "name": "@tidal-music/api",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "files": [
6
+ "dist"
7
+ ],
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "ssh://git@github.com:tidal-music/tidal-sdk-web.git"
11
+ },
12
+ "license": "Apache-2.0",
13
+ "module": "dist/index.js",
14
+ "types": "dist/index.d.ts",
15
+ "exports": {
16
+ "default": "./dist/index.js",
17
+ "import": "./dist/index.js"
18
+ },
19
+ "dependencies": {
20
+ "openapi-fetch": "0.12.0",
21
+ "@tidal-music/api": "0.1.0"
22
+ },
23
+ "devDependencies": {
24
+ "@vitest/coverage-v8": "2.0.4",
25
+ "@vitest/ui": "2.0.4",
26
+ "openapi-typescript": "7.4.0",
27
+ "typescript": "5.6.2",
28
+ "vite": "5.4.6",
29
+ "vite-plugin-dts": "4.2.1",
30
+ "vitest": "2.0.4",
31
+ "@tidal-music/common": "^0.1.5",
32
+ "@tidal-music/auth": "^1.3.3"
33
+ },
34
+ "scripts": {
35
+ "build": "vite build",
36
+ "build:dev": "vite build -m development",
37
+ "clean": "rm -rf coverage dist .eslintcache",
38
+ "dev": "vite --debug --cors -c=./vite.config.ts",
39
+ "lint": "eslint . --cache --cache-strategy content",
40
+ "lint:ci": "eslint . --quiet",
41
+ "lint:fix": "pnpm run lint --fix",
42
+ "preview": "vite preview",
43
+ "generateTypes": "openapi-typescript",
44
+ "test": "vitest",
45
+ "test:coverage": "pnpm run test --coverage",
46
+ "test:ui": "pnpm run test:coverage --ui",
47
+ "typecheck": "tsc"
48
+ }
49
+ }