q-fi-core 2.3.1

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 (79) hide show
  1. package/CHANGELOG.md +109 -0
  2. package/LICENSE +1 -0
  3. package/README.md +186 -0
  4. package/dist/api/api.d.ts +78 -0
  5. package/dist/api/api.js +182 -0
  6. package/dist/api/cache.d.ts +3 -0
  7. package/dist/api/cache.js +12 -0
  8. package/dist/api/index.d.ts +2 -0
  9. package/dist/api/index.js +18 -0
  10. package/dist/api/request.d.ts +23 -0
  11. package/dist/api/request.js +88 -0
  12. package/dist/converter/deezer.d.ts +3 -0
  13. package/dist/converter/deezer.js +45 -0
  14. package/dist/converter/index.d.ts +5 -0
  15. package/dist/converter/index.js +34 -0
  16. package/dist/converter/parse.d.ts +18 -0
  17. package/dist/converter/parse.js +176 -0
  18. package/dist/converter/spotify.d.ts +40 -0
  19. package/dist/converter/spotify.js +154 -0
  20. package/dist/converter/tidal.d.ts +146 -0
  21. package/dist/converter/tidal.js +199 -0
  22. package/dist/converter/youtube.d.ts +6 -0
  23. package/dist/converter/youtube.js +102 -0
  24. package/dist/index.d.ts +6 -0
  25. package/dist/index.js +24 -0
  26. package/dist/lib/decrypt.d.ts +9 -0
  27. package/dist/lib/decrypt.js +63 -0
  28. package/dist/lib/fast-lru.d.ts +63 -0
  29. package/dist/lib/fast-lru.js +121 -0
  30. package/dist/lib/get-url.d.ts +16 -0
  31. package/dist/lib/get-url.js +154 -0
  32. package/dist/lib/http.d.ts +66 -0
  33. package/dist/lib/http.js +235 -0
  34. package/dist/lib/metaflac-js.d.ts +124 -0
  35. package/dist/lib/metaflac-js.js +343 -0
  36. package/dist/lib/request.d.ts +18 -0
  37. package/dist/lib/request.js +86 -0
  38. package/dist/metadata-writer/abumCover.d.ts +10 -0
  39. package/dist/metadata-writer/abumCover.js +37 -0
  40. package/dist/metadata-writer/flacmetata.d.ts +3 -0
  41. package/dist/metadata-writer/flacmetata.js +80 -0
  42. package/dist/metadata-writer/getTrackLyrics.d.ts +2 -0
  43. package/dist/metadata-writer/getTrackLyrics.js +26 -0
  44. package/dist/metadata-writer/id3.d.ts +3 -0
  45. package/dist/metadata-writer/id3.js +119 -0
  46. package/dist/metadata-writer/index.d.ts +9 -0
  47. package/dist/metadata-writer/index.js +44 -0
  48. package/dist/metadata-writer/musixmatchLyrics.d.ts +1 -0
  49. package/dist/metadata-writer/musixmatchLyrics.js +39 -0
  50. package/dist/metadata-writer/useragents.d.ts +1 -0
  51. package/dist/metadata-writer/useragents.js +86 -0
  52. package/dist/types/album.d.ts +123 -0
  53. package/dist/types/album.js +2 -0
  54. package/dist/types/artist.d.ts +36 -0
  55. package/dist/types/artist.js +2 -0
  56. package/dist/types/channel.d.ts +33 -0
  57. package/dist/types/channel.js +2 -0
  58. package/dist/types/index.d.ts +10 -0
  59. package/dist/types/index.js +26 -0
  60. package/dist/types/playlist-channel.d.ts +81 -0
  61. package/dist/types/playlist-channel.js +2 -0
  62. package/dist/types/playlist.d.ts +49 -0
  63. package/dist/types/playlist.js +2 -0
  64. package/dist/types/profile.d.ts +29 -0
  65. package/dist/types/profile.js +2 -0
  66. package/dist/types/radio.d.ts +7 -0
  67. package/dist/types/radio.js +2 -0
  68. package/dist/types/search.d.ts +79 -0
  69. package/dist/types/search.js +2 -0
  70. package/dist/types/show.d.ts +61 -0
  71. package/dist/types/show.js +2 -0
  72. package/dist/types/tracks.d.ts +144 -0
  73. package/dist/types/tracks.js +2 -0
  74. package/dist/types/user.d.ts +16 -0
  75. package/dist/types/user.js +2 -0
  76. package/package.json +69 -0
  77. package/types/index.d.ts +1 -0
  78. package/types/index.js +3 -0
  79. package/types/package.json +4 -0
@@ -0,0 +1,121 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ /**
4
+ * Fast LRU & TTL cache
5
+ * @param {Integer} options.max - Max entries in the cache. @default Infinity
6
+ * @param {Integer} options.ttl - Timeout before removing entries. @default Infinity
7
+ */
8
+ class FastLRU {
9
+ constructor({ maxSize = Infinity, ttl = 0 }) {
10
+ // Default options
11
+ this._max = maxSize;
12
+ this._ttl = ttl;
13
+ this._cache = new Map();
14
+ // Metadata for entries
15
+ this._meta = {};
16
+ }
17
+ /**
18
+ * Add new entry
19
+ */
20
+ set(key, value, ttl = this._ttl) {
21
+ // Execution time
22
+ const time = Date.now();
23
+ // Remvove least recently used elements if exceeds max bytes
24
+ if (this._cache.size >= this._max) {
25
+ const items = Object.values(this._meta);
26
+ if (this._ttl > 0) {
27
+ for (const item of items) {
28
+ if (item.expire < time) {
29
+ this.delete(item.key);
30
+ }
31
+ }
32
+ }
33
+ if (this._cache.size >= this._max) {
34
+ const least = items.sort((a, b) => a.hits - b.hits)[0];
35
+ this.delete(least.key);
36
+ }
37
+ }
38
+ // Override if key already set
39
+ this._cache.set(key, value);
40
+ this._meta[key] = {
41
+ key,
42
+ hits: 0,
43
+ expire: time + ttl,
44
+ };
45
+ }
46
+ /**
47
+ * Get entry
48
+ */
49
+ get(key) {
50
+ if (this._cache.has(key)) {
51
+ const item = this._cache.get(key);
52
+ if (this._ttl > 0) {
53
+ const time = Date.now();
54
+ if (this._meta[key].expire < time) {
55
+ this.delete(key);
56
+ return undefined;
57
+ }
58
+ }
59
+ this._meta[key].hits++;
60
+ return item;
61
+ }
62
+ }
63
+ /**
64
+ * Get without hitting hits
65
+ */
66
+ peek(key) {
67
+ return this._cache.get(key);
68
+ }
69
+ /**
70
+ * Remove entry
71
+ */
72
+ delete(key) {
73
+ delete this._meta[key];
74
+ this._cache.delete(key);
75
+ }
76
+ /**
77
+ * Remove all entries
78
+ */
79
+ clear() {
80
+ this._cache.clear();
81
+ this._meta = {};
82
+ }
83
+ /**
84
+ * Check has entry
85
+ */
86
+ has(key) {
87
+ return this._cache.has(key);
88
+ }
89
+ /**
90
+ * Get all kies
91
+ * @returns {Iterator} Iterator on all kies
92
+ */
93
+ keys() {
94
+ return this._cache.keys();
95
+ }
96
+ /**
97
+ * Iterate over values
98
+ */
99
+ values() {
100
+ return this._cache.values();
101
+ }
102
+ /**
103
+ * Iterate over entries
104
+ */
105
+ entries() {
106
+ return this._cache.entries();
107
+ }
108
+ /**
109
+ * For each
110
+ */
111
+ forEach(cb) {
112
+ return this._cache.forEach(cb);
113
+ }
114
+ /**
115
+ * Entries total size
116
+ */
117
+ get size() {
118
+ return this._cache.size;
119
+ }
120
+ }
121
+ exports.default = FastLRU;
@@ -0,0 +1,16 @@
1
+ import type { trackType } from '../types';
2
+ export declare class WrongLicense extends Error {
3
+ constructor(format: string);
4
+ }
5
+ export declare class GeoBlocked extends Error {
6
+ constructor(country: string);
7
+ }
8
+ /**
9
+ * @param track Track info json returned from `getTrackInfo`
10
+ * @param quality 1 = 128kbps, 3 = 320kbps and 9 = flac (around 1411kbps)
11
+ */
12
+ export declare const getTrackDownloadUrl: (track: trackType, quality: number) => Promise<{
13
+ trackUrl: string;
14
+ isEncrypted: boolean;
15
+ fileSize: number;
16
+ } | null>;
@@ -0,0 +1,154 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getTrackDownloadUrl = exports.GeoBlocked = exports.WrongLicense = void 0;
7
+ const decrypt_1 = require("../lib/decrypt");
8
+ const http_1 = require("../lib/http");
9
+ const request_1 = __importDefault(require("../lib/request"));
10
+ class WrongLicense extends Error {
11
+ constructor(format) {
12
+ super();
13
+ this.name = 'WrongLicense';
14
+ this.message = `Your account can't stream ${format} tracks`;
15
+ }
16
+ }
17
+ exports.WrongLicense = WrongLicense;
18
+ class GeoBlocked extends Error {
19
+ constructor(country) {
20
+ super();
21
+ this.name = 'GeoBlocked';
22
+ this.message = `This track is not available in your country (${country})`;
23
+ }
24
+ }
25
+ exports.GeoBlocked = GeoBlocked;
26
+ let user_data = null;
27
+ const getTrackFileSize = (track, quality) => {
28
+ switch (quality) {
29
+ case 9:
30
+ return Number(track.FILESIZE_FLAC);
31
+ case 3:
32
+ return Number(track.FILESIZE_MP3_320);
33
+ case 1:
34
+ return Number(track.FILESIZE_MP3_128);
35
+ default:
36
+ return 0;
37
+ }
38
+ };
39
+ const dzAuthenticate = async () => {
40
+ const { data } = await request_1.default.get('https://www.deezer.com/ajax/gw-light.php', {
41
+ params: {
42
+ method: 'deezer.getUserData',
43
+ api_version: '1.0',
44
+ api_token: 'null',
45
+ },
46
+ });
47
+ user_data = {
48
+ license_token: data.results.USER.OPTIONS.license_token,
49
+ can_stream_lossless: data.results.USER.OPTIONS.web_lossless || data.results.USER.OPTIONS.mobile_loseless,
50
+ can_stream_hq: data.results.USER.OPTIONS.web_hq || data.results.USER.OPTIONS.mobile_hq,
51
+ country: data.results.COUNTRY,
52
+ };
53
+ return user_data;
54
+ };
55
+ const getTrackUrlFromServer = async (track_token, format) => {
56
+ const user = user_data ? user_data : await dzAuthenticate();
57
+ if ((format === 'FLAC' && !user.can_stream_lossless) || (format === 'MP3_320' && !user.can_stream_hq)) {
58
+ throw new WrongLicense(format);
59
+ }
60
+ const { data } = await request_1.default.post('https://media.deezer.com/v1/get_url', {
61
+ license_token: user.license_token,
62
+ media: [
63
+ {
64
+ type: 'FULL',
65
+ formats: [{ format, cipher: 'BF_CBC_STRIPE' }],
66
+ },
67
+ ],
68
+ track_tokens: [track_token],
69
+ });
70
+ if (data.data.length > 0) {
71
+ if (data.data[0].errors) {
72
+ if (data.data[0].errors[0].code === 2002) {
73
+ throw new GeoBlocked(user.country);
74
+ }
75
+ throw new Error(Object.entries(data.data[0].errors[0]).join(', '));
76
+ }
77
+ return data.data[0].media.length > 0 ? data.data[0].media[0].sources[0].url : null;
78
+ }
79
+ return null;
80
+ };
81
+ /**
82
+ * @param track Track info json returned from `getTrackInfo`
83
+ * @param quality 1 = 128kbps, 3 = 320kbps and 9 = flac (around 1411kbps)
84
+ */
85
+ const getTrackDownloadUrl = async (track, quality) => {
86
+ let wrongLicense = null;
87
+ let geoBlocked = null;
88
+ let formatName;
89
+ switch (quality) {
90
+ case 9:
91
+ formatName = 'FLAC';
92
+ break;
93
+ case 3:
94
+ formatName = 'MP3_320';
95
+ break;
96
+ case 1:
97
+ formatName = 'MP3_128';
98
+ break;
99
+ default:
100
+ throw new Error(`Unknown quality ${quality}`);
101
+ }
102
+ // Get URL with the official API
103
+ try {
104
+ const url = await getTrackUrlFromServer(track.TRACK_TOKEN, formatName);
105
+ if (url) {
106
+ return {
107
+ trackUrl: url,
108
+ isEncrypted: url.includes('/mobile/') || url.includes('/media/'),
109
+ fileSize: getTrackFileSize(track, quality),
110
+ };
111
+ }
112
+ }
113
+ catch (err) {
114
+ if (err instanceof WrongLicense) {
115
+ wrongLicense = err;
116
+ }
117
+ else if (err instanceof GeoBlocked) {
118
+ geoBlocked = err;
119
+ }
120
+ else {
121
+ throw err;
122
+ }
123
+ }
124
+ // Fallback to the old method
125
+ if (track.MD5_ORIGIN) {
126
+ const filename = (0, decrypt_1.getSongFileName)(track, quality); // encrypted file name
127
+ const url = `https://e-cdns-proxy-${track.MD5_ORIGIN[0]}.dzcdn.net/mobile/1/${filename}`;
128
+ const fileSize = await testUrl(url);
129
+ if (fileSize > 0) {
130
+ return {
131
+ trackUrl: url,
132
+ isEncrypted: url.includes('/mobile/') || url.includes('/media/'),
133
+ fileSize: fileSize,
134
+ };
135
+ }
136
+ }
137
+ if (wrongLicense) {
138
+ throw wrongLicense;
139
+ }
140
+ if (geoBlocked) {
141
+ throw geoBlocked;
142
+ }
143
+ return null;
144
+ };
145
+ exports.getTrackDownloadUrl = getTrackDownloadUrl;
146
+ const testUrl = async (url) => {
147
+ try {
148
+ const { headers } = await (0, http_1.headRequest)(url);
149
+ return Number(headers['content-length']);
150
+ }
151
+ catch (err) {
152
+ return 0;
153
+ }
154
+ };
@@ -0,0 +1,66 @@
1
+ /// <reference types="node" />
2
+ /// <reference types="node" />
3
+ import { IncomingHttpHeaders } from 'http';
4
+ type HttpMethod = 'GET' | 'POST' | 'HEAD';
5
+ type ResponseType = 'buffer' | 'json' | 'text';
6
+ type QueryValue = string | number | boolean | null | undefined;
7
+ type QueryInput = QueryValue | QueryValue[];
8
+ export type HttpHeaders = Record<string, string>;
9
+ export type HttpQuery = Record<string, QueryInput>;
10
+ export interface HttpRequestConfig {
11
+ headers?: HttpHeaders;
12
+ params?: HttpQuery;
13
+ timeout?: number;
14
+ responseType?: ResponseType;
15
+ }
16
+ interface RequestDescriptor {
17
+ data?: unknown;
18
+ headers?: HttpHeaders;
19
+ method: HttpMethod;
20
+ params?: HttpQuery;
21
+ responseType: ResponseType;
22
+ timeout: number;
23
+ url: string;
24
+ }
25
+ export interface HttpResponse<T> {
26
+ config: RequestDescriptor;
27
+ data: T;
28
+ headers: IncomingHttpHeaders;
29
+ request: {
30
+ res: {
31
+ responseUrl: string;
32
+ };
33
+ };
34
+ status: number;
35
+ }
36
+ export declare class HttpStatusError extends Error {
37
+ body: Buffer;
38
+ headers: IncomingHttpHeaders;
39
+ statusCode: number;
40
+ constructor(statusCode: number, headers: IncomingHttpHeaders, body: Buffer);
41
+ }
42
+ export declare class HttpClient {
43
+ defaults: {
44
+ baseURL?: string;
45
+ headers: HttpHeaders;
46
+ maxRedirects: number;
47
+ params: HttpQuery;
48
+ timeout: number;
49
+ };
50
+ constructor(defaults?: {
51
+ baseURL?: string;
52
+ headers?: HttpHeaders;
53
+ maxRedirects?: number;
54
+ params?: HttpQuery;
55
+ timeout?: number;
56
+ });
57
+ get<T = unknown>(url: string, config?: HttpRequestConfig): Promise<HttpResponse<T>>;
58
+ post<T = unknown>(url: string, body?: unknown, config?: HttpRequestConfig): Promise<HttpResponse<T>>;
59
+ head(url: string, config?: Omit<HttpRequestConfig, 'responseType'>): Promise<HttpResponse<Buffer>>;
60
+ private request;
61
+ }
62
+ export declare const getBuffer: (url: string, config?: HttpRequestConfig) => Promise<Buffer>;
63
+ export declare const getJson: <T = unknown>(url: string, config?: HttpRequestConfig) => Promise<T>;
64
+ export declare const getText: (url: string, config?: HttpRequestConfig) => Promise<string>;
65
+ export declare const headRequest: (url: string, config?: Omit<HttpRequestConfig, 'responseType'>) => Promise<HttpResponse<Buffer>>;
66
+ export {};
@@ -0,0 +1,235 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.headRequest = exports.getText = exports.getJson = exports.getBuffer = exports.HttpClient = exports.HttpStatusError = void 0;
4
+ const http_1 = require("http");
5
+ const https_1 = require("https");
6
+ const zlib_1 = require("zlib");
7
+ const httpAgent = new http_1.Agent({ keepAlive: true });
8
+ const httpsAgent = new https_1.Agent({ keepAlive: true });
9
+ class HttpStatusError extends Error {
10
+ constructor(statusCode, headers, body) {
11
+ super(`Request failed with status code ${statusCode}`);
12
+ this.name = 'HttpStatusError';
13
+ this.statusCode = statusCode;
14
+ this.headers = headers;
15
+ this.body = body;
16
+ }
17
+ }
18
+ exports.HttpStatusError = HttpStatusError;
19
+ class HttpClient {
20
+ constructor(defaults = {}) {
21
+ var _a, _b;
22
+ this.defaults = {
23
+ baseURL: defaults.baseURL,
24
+ headers: defaults.headers ? normalizeHeaders(defaults.headers) : {},
25
+ maxRedirects: (_a = defaults.maxRedirects) !== null && _a !== void 0 ? _a : 5,
26
+ params: defaults.params ? { ...defaults.params } : {},
27
+ timeout: (_b = defaults.timeout) !== null && _b !== void 0 ? _b : 15000,
28
+ };
29
+ }
30
+ get(url, config = {}) {
31
+ return this.request('GET', url, undefined, config);
32
+ }
33
+ post(url, body, config = {}) {
34
+ return this.request('POST', url, body, config);
35
+ }
36
+ head(url, config = {}) {
37
+ return this.request('HEAD', url, undefined, { ...config, responseType: 'buffer' });
38
+ }
39
+ async request(method, url, body, config = {}) {
40
+ var _a, _b;
41
+ const responseType = (_a = config.responseType) !== null && _a !== void 0 ? _a : 'json';
42
+ const timeout = (_b = config.timeout) !== null && _b !== void 0 ? _b : this.defaults.timeout;
43
+ const headers = normalizeHeaders({ ...this.defaults.headers, ...config.headers });
44
+ const params = { ...this.defaults.params, ...config.params };
45
+ const rawResponse = await requestRaw({
46
+ baseURL: this.defaults.baseURL,
47
+ body,
48
+ headers,
49
+ maxRedirects: this.defaults.maxRedirects,
50
+ method,
51
+ params,
52
+ timeout,
53
+ url,
54
+ });
55
+ return {
56
+ config: {
57
+ data: body,
58
+ headers,
59
+ method,
60
+ params,
61
+ responseType,
62
+ timeout,
63
+ url,
64
+ },
65
+ data: parseResponseBody(rawResponse, responseType),
66
+ headers: rawResponse.headers,
67
+ request: {
68
+ res: {
69
+ responseUrl: rawResponse.url,
70
+ },
71
+ },
72
+ status: rawResponse.status,
73
+ };
74
+ }
75
+ }
76
+ exports.HttpClient = HttpClient;
77
+ const requestRaw = async (config, redirectCount = 0) => {
78
+ const requestUrl = buildUrl(config.url, config.baseURL, config.params);
79
+ const headers = normalizeHeaders(config.headers);
80
+ const serializedBody = serializeBody(config.body, headers);
81
+ if (serializedBody && !headers['content-length']) {
82
+ headers['content-length'] = String(serializedBody.length);
83
+ }
84
+ return await new Promise((resolve, reject) => {
85
+ var _a;
86
+ const isHttps = requestUrl.protocol === 'https:';
87
+ const requestFn = isHttps ? https_1.request : http_1.request;
88
+ const req = requestFn({
89
+ agent: isHttps ? httpsAgent : httpAgent,
90
+ headers,
91
+ hostname: requestUrl.hostname,
92
+ method: config.method,
93
+ path: requestUrl.pathname + requestUrl.search,
94
+ port: requestUrl.port,
95
+ protocol: requestUrl.protocol,
96
+ }, (response) => {
97
+ var _a, _b;
98
+ const status = (_a = response.statusCode) !== null && _a !== void 0 ? _a : 0;
99
+ const locationHeader = response.headers.location;
100
+ const location = Array.isArray(locationHeader) ? locationHeader[0] : locationHeader;
101
+ if (location && isRedirectStatus(status) && redirectCount < ((_b = config.maxRedirects) !== null && _b !== void 0 ? _b : 5)) {
102
+ response.resume();
103
+ const redirectedMethod = status === 303 || ((status === 301 || status === 302) && config.method === 'POST') ? 'GET' : config.method;
104
+ const redirectedHeaders = { ...headers };
105
+ if (redirectedMethod === 'GET' || redirectedMethod === 'HEAD') {
106
+ delete redirectedHeaders['content-length'];
107
+ delete redirectedHeaders['content-type'];
108
+ }
109
+ requestRaw({
110
+ ...config,
111
+ baseURL: undefined,
112
+ body: redirectedMethod === 'POST' ? config.body : undefined,
113
+ headers: redirectedHeaders,
114
+ method: redirectedMethod,
115
+ url: new URL(location, requestUrl).toString(),
116
+ }, redirectCount + 1)
117
+ .then(resolve)
118
+ .catch(reject);
119
+ return;
120
+ }
121
+ const chunks = [];
122
+ response.on('data', (chunk) => {
123
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
124
+ });
125
+ response.on('end', () => {
126
+ try {
127
+ const body = decodeResponseBuffer(Buffer.concat(chunks), response.headers['content-encoding']);
128
+ if (status < 200 || status >= 300) {
129
+ reject(new HttpStatusError(status, response.headers, body));
130
+ return;
131
+ }
132
+ resolve({
133
+ body,
134
+ headers: response.headers,
135
+ status,
136
+ url: requestUrl.toString(),
137
+ });
138
+ }
139
+ catch (err) {
140
+ reject(err);
141
+ }
142
+ });
143
+ });
144
+ req.on('error', reject);
145
+ req.setTimeout((_a = config.timeout) !== null && _a !== void 0 ? _a : 15000, () => {
146
+ var _a;
147
+ req.destroy(new Error(`Request timed out after ${(_a = config.timeout) !== null && _a !== void 0 ? _a : 15000}ms`));
148
+ });
149
+ if (serializedBody) {
150
+ req.write(serializedBody);
151
+ }
152
+ req.end();
153
+ });
154
+ };
155
+ const buildUrl = (url, baseURL, params) => {
156
+ const parsedUrl = new URL(resolveUrl(url, baseURL));
157
+ if (params) {
158
+ for (const [key, input] of Object.entries(params)) {
159
+ if (Array.isArray(input)) {
160
+ for (const value of input) {
161
+ if (value !== undefined && value !== null) {
162
+ parsedUrl.searchParams.append(key, String(value));
163
+ }
164
+ }
165
+ }
166
+ else if (input !== undefined && input !== null) {
167
+ parsedUrl.searchParams.set(key, String(input));
168
+ }
169
+ }
170
+ }
171
+ return parsedUrl;
172
+ };
173
+ const resolveUrl = (url, baseURL) => {
174
+ if (!baseURL || isAbsoluteUrl(url)) {
175
+ return url;
176
+ }
177
+ return `${baseURL.replace(/\/+$/, '')}/${url.replace(/^\/+/, '')}`;
178
+ };
179
+ const normalizeHeaders = (headers = {}) => {
180
+ const normalizedHeaders = {};
181
+ for (const [key, value] of Object.entries(headers)) {
182
+ normalizedHeaders[key.toLowerCase()] = value;
183
+ }
184
+ return normalizedHeaders;
185
+ };
186
+ const serializeBody = (body, headers) => {
187
+ if (body === undefined) {
188
+ return undefined;
189
+ }
190
+ if (Buffer.isBuffer(body)) {
191
+ return body;
192
+ }
193
+ if (typeof body === 'string') {
194
+ return Buffer.from(body);
195
+ }
196
+ if (!headers['content-type']) {
197
+ headers['content-type'] = 'application/json; charset=UTF-8';
198
+ }
199
+ return Buffer.from(JSON.stringify(body));
200
+ };
201
+ const decodeResponseBuffer = (buffer, contentEncoding) => {
202
+ var _a, _b;
203
+ const encoding = (_b = (_a = (Array.isArray(contentEncoding) ? contentEncoding[0] : contentEncoding)) === null || _a === void 0 ? void 0 : _a.split(',')[0]) === null || _b === void 0 ? void 0 : _b.trim();
204
+ switch (encoding) {
205
+ case 'br':
206
+ return (0, zlib_1.brotliDecompressSync)(buffer);
207
+ case 'deflate':
208
+ return (0, zlib_1.inflateSync)(buffer);
209
+ case 'gzip':
210
+ return (0, zlib_1.gunzipSync)(buffer);
211
+ default:
212
+ return buffer;
213
+ }
214
+ };
215
+ const parseResponseBody = (response, responseType) => {
216
+ if (responseType === 'buffer') {
217
+ return response.body;
218
+ }
219
+ const text = response.body.toString('utf-8');
220
+ if (responseType === 'text') {
221
+ return text;
222
+ }
223
+ return JSON.parse(text);
224
+ };
225
+ const isRedirectStatus = (status) => [301, 302, 303, 307, 308].includes(status);
226
+ const isAbsoluteUrl = (url) => /^[a-z][a-z\d+\-.]*:\/\//i.test(url);
227
+ const defaultClient = new HttpClient();
228
+ const getBuffer = async (url, config = {}) => (await defaultClient.get(url, { ...config, responseType: 'buffer' })).data;
229
+ exports.getBuffer = getBuffer;
230
+ const getJson = async (url, config = {}) => (await defaultClient.get(url, { ...config, responseType: 'json' })).data;
231
+ exports.getJson = getJson;
232
+ const getText = async (url, config = {}) => (await defaultClient.get(url, { ...config, responseType: 'text' })).data;
233
+ exports.getText = getText;
234
+ const headRequest = async (url, config = {}) => await defaultClient.head(url, config);
235
+ exports.headRequest = headRequest;