gerdur-core 1.0.2 → 1.0.4

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 CHANGED
@@ -1,5 +1,23 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.0.4 - 2026-08-31
4
+
5
+ ### Added
6
+
7
+ - `resolveDownloadUrls(tracks, qualities)` — resolve download URLs for a whole album/playlist in **one** `media.deezer.com/v1/get_url` POST (`track_tokens[]` + an ordered `formats[]` fallback), instead of one request per track re-tried per quality. ~19× faster URL resolution for a 14-track album. Returns one `ResolvedUrl | null` per input track, in order. `formatName(quality)` is also exported.
8
+ - `httpAgent` / `httpsAgent` — the shared keep-alive connection pools are now exported so downstream apps can hand them to `got`/`undici` and reuse the same sockets for downloads. `getBuffer` / `getJson` / `getText` are exported too.
9
+
10
+ ### Changed
11
+
12
+ - **Shared HTTP agents are tuned and bounded**: `keepAlive`, `maxSockets: 64` (was the Node default of `Infinity`), `maxFreeSockets: 16`, `scheduling: 'lifo'`, 30 s keep-alive. Caps a pathological fan-out from opening hundreds of sockets to `api.deezer.com`, while leaving generous headroom over the converter's concurrency.
13
+ - **In-flight request coalescing** in the API layer: concurrent identical gateway / public-API calls (e.g. every track of one album asking for the same album info while tagging) now share a single request instead of each missing the still-empty cache and hitting the wire.
14
+
15
+ ## 1.0.3 - 2026-08-30
16
+
17
+ ### Changed
18
+
19
+ - `getTrackDownloadUrl`: when `media.deezer.com/v1/get_url` returns 403/429/5xx (throttling or a stale license token), re-authenticate and retry with exponential backoff (up to 3×); if it still fails, fall through to the token-free legacy CDN instead of throwing.
20
+
3
21
  ## 1.0.2 - 2026-08-30
4
22
 
5
23
  ### Fixed
@@ -6,6 +6,38 @@ Object.defineProperty(exports, "__esModule", { value: true });
6
6
  exports.requestPublicApi = exports.requestGet = exports.requestLight = exports.request = void 0;
7
7
  const request_1 = __importDefault(require("../lib/request"));
8
8
  const cache_1 = __importDefault(require("./cache"));
9
+ /**
10
+ * In-flight request coalescing (single-flight).
11
+ *
12
+ * The LRU only helps *after* a response lands. During a batch download the
13
+ * pipeline fires many identical metadata calls at once — e.g. tagging 14 tracks
14
+ * of one album triggers 14 concurrent `album/<id>` lookups — and every one of
15
+ * them misses the still-empty cache and hits the network. Here a second caller
16
+ * for a key already in flight awaits the same promise instead, so the wire sees
17
+ * exactly one request. Entries are removed as soon as they settle; the LRU takes
18
+ * over from there.
19
+ */
20
+ const inFlight = new Map();
21
+ const coalesce = (cacheKey, fetcher) => {
22
+ const cached = cache_1.default.get(cacheKey);
23
+ if (cached) {
24
+ return Promise.resolve(cached);
25
+ }
26
+ const pending = inFlight.get(cacheKey);
27
+ if (pending) {
28
+ return pending;
29
+ }
30
+ const promise = (async () => {
31
+ try {
32
+ return await fetcher();
33
+ }
34
+ finally {
35
+ inFlight.delete(cacheKey);
36
+ }
37
+ })();
38
+ inFlight.set(cacheKey, promise);
39
+ return promise;
40
+ };
9
41
  /**
10
42
  * Make POST requests to deezer api
11
43
  * @param {Object} body post body
@@ -13,17 +45,14 @@ const cache_1 = __importDefault(require("./cache"));
13
45
  */
14
46
  const request = async (body, method) => {
15
47
  const cacheKey = method + ':' + Object.entries(body).join(':');
16
- const cache = cache_1.default.get(cacheKey);
17
- if (cache) {
18
- return cache;
19
- }
20
- const { data: { error, results }, } = await request_1.default.post('/gateway.php', body, { params: { method } });
21
- if (Object.keys(results).length > 0) {
22
- cache_1.default.set(cacheKey, results);
23
- return results;
24
- }
25
- const errorMessage = Object.entries(error).join(', ');
26
- throw new Error(errorMessage);
48
+ return coalesce(cacheKey, async () => {
49
+ const { data: { error, results }, } = await request_1.default.post('/gateway.php', body, { params: { method } });
50
+ if (Object.keys(results).length > 0) {
51
+ cache_1.default.set(cacheKey, results);
52
+ return results;
53
+ }
54
+ throw new Error(Object.entries(error).join(', '));
55
+ });
27
56
  };
28
57
  exports.request = request;
29
58
  /**
@@ -33,19 +62,16 @@ exports.request = request;
33
62
  */
34
63
  const requestLight = async (body, method) => {
35
64
  const cacheKey = method + ':' + Object.entries(body).join(':');
36
- const cache = cache_1.default.get(cacheKey);
37
- if (cache) {
38
- return cache;
39
- }
40
- const { data: { error, results }, } = await request_1.default.post('https://www.deezer.com/ajax/gw-light.php', body, {
41
- params: { method, api_version: '1.0' },
65
+ return coalesce(cacheKey, async () => {
66
+ const { data: { error, results }, } = await request_1.default.post('https://www.deezer.com/ajax/gw-light.php', body, {
67
+ params: { method, api_version: '1.0' },
68
+ });
69
+ if (Object.keys(results).length > 0) {
70
+ cache_1.default.set(cacheKey, results);
71
+ return results;
72
+ }
73
+ throw new Error(Object.entries(error).join(', '));
42
74
  });
43
- if (Object.keys(results).length > 0) {
44
- cache_1.default.set(cacheKey, results);
45
- return results;
46
- }
47
- const errorMessage = Object.entries(error).join(', ');
48
- throw new Error(errorMessage);
49
75
  };
50
76
  exports.requestLight = requestLight;
51
77
  /**
@@ -55,17 +81,14 @@ exports.requestLight = requestLight;
55
81
  */
56
82
  const requestGet = async (method, params = {}, key = 'get_request') => {
57
83
  const cacheKey = method + key;
58
- const cache = cache_1.default.get(cacheKey);
59
- if (cache) {
60
- return cache;
61
- }
62
- const { data: { error, results }, } = await request_1.default.get('/gateway.php', { params: { method, ...params } });
63
- if (Object.keys(results).length > 0) {
64
- cache_1.default.set(cacheKey, results);
65
- return results;
66
- }
67
- const errorMessage = Object.entries(error).join(', ');
68
- throw new Error(errorMessage);
84
+ return coalesce(cacheKey, async () => {
85
+ const { data: { error, results }, } = await request_1.default.get('/gateway.php', { params: { method, ...params } });
86
+ if (Object.keys(results).length > 0) {
87
+ cache_1.default.set(cacheKey, results);
88
+ return results;
89
+ }
90
+ throw new Error(Object.entries(error).join(', '));
91
+ });
69
92
  };
70
93
  exports.requestGet = requestGet;
71
94
  /**
@@ -73,16 +96,14 @@ exports.requestGet = requestGet;
73
96
  * @param {String} slug endpoint
74
97
  */
75
98
  const requestPublicApi = async (slug) => {
76
- const cache = cache_1.default.get(slug);
77
- if (cache) {
78
- return cache;
79
- }
80
- const { data } = await request_1.default.get('https://api.deezer.com' + slug);
81
- if (data.error) {
82
- const errorMessage = Object.entries(data.error).join(', ');
83
- throw new Error(errorMessage);
84
- }
85
- cache_1.default.set(slug, data);
86
- return data;
99
+ return coalesce(slug, async () => {
100
+ const { data } = await request_1.default.get('https://api.deezer.com' + slug);
101
+ if (data.error) {
102
+ const errorMessage = Object.entries(data.error).join(', ');
103
+ throw new Error(errorMessage);
104
+ }
105
+ cache_1.default.set(slug, data);
106
+ return data;
107
+ });
87
108
  };
88
109
  exports.requestPublicApi = requestPublicApi;
package/dist/index.d.ts CHANGED
@@ -3,4 +3,5 @@ export * from './api';
3
3
  export * from './converter';
4
4
  export * from './lib/decrypt';
5
5
  export * from './lib/get-url';
6
+ export { httpAgent, httpsAgent, getBuffer, getJson, getText } from './lib/http';
6
7
  export * from './metadata-writer';
package/dist/index.js CHANGED
@@ -14,11 +14,17 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
14
  for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
15
  };
16
16
  Object.defineProperty(exports, "__esModule", { value: true });
17
- exports.initDeezerApi = void 0;
17
+ exports.getText = exports.getJson = exports.getBuffer = exports.httpsAgent = exports.httpAgent = exports.initDeezerApi = void 0;
18
18
  var request_1 = require("./lib/request");
19
19
  Object.defineProperty(exports, "initDeezerApi", { enumerable: true, get: function () { return request_1.initDeezerApi; } });
20
20
  __exportStar(require("./api"), exports);
21
21
  __exportStar(require("./converter"), exports);
22
22
  __exportStar(require("./lib/decrypt"), exports);
23
23
  __exportStar(require("./lib/get-url"), exports);
24
+ var http_1 = require("./lib/http");
25
+ Object.defineProperty(exports, "httpAgent", { enumerable: true, get: function () { return http_1.httpAgent; } });
26
+ Object.defineProperty(exports, "httpsAgent", { enumerable: true, get: function () { return http_1.httpsAgent; } });
27
+ Object.defineProperty(exports, "getBuffer", { enumerable: true, get: function () { return http_1.getBuffer; } });
28
+ Object.defineProperty(exports, "getJson", { enumerable: true, get: function () { return http_1.getJson; } });
29
+ Object.defineProperty(exports, "getText", { enumerable: true, get: function () { return http_1.getText; } });
24
30
  __exportStar(require("./metadata-writer"), exports);
@@ -13,6 +13,8 @@ export declare class ExpiredTrackToken extends Error {
13
13
  readonly sngId: string;
14
14
  constructor(sngId: string);
15
15
  }
16
+ /** quality code -> the `format` string the media API expects */
17
+ export declare const formatName: (quality: number) => string;
16
18
  /**
17
19
  * @param track Track info json returned from `getTrackInfo`
18
20
  * @param quality 1 = 128kbps, 3 = 320kbps and 9 = flac (around 1411kbps)
@@ -22,3 +24,22 @@ export declare const getTrackDownloadUrl: (track: trackType, quality: number) =>
22
24
  isEncrypted: boolean;
23
25
  fileSize: number;
24
26
  } | null>;
27
+ export interface ResolvedUrl {
28
+ trackUrl: string;
29
+ isEncrypted: boolean;
30
+ fileSize: number;
31
+ /** the format Deezer actually returned, e.g. `'FLAC'` */
32
+ format: string;
33
+ }
34
+ /**
35
+ * Resolve download URLs for many tracks in a **single** `get_url` request.
36
+ *
37
+ * `qualities` is an ordered preference list (e.g. `[9, 3, 1]`): Deezer returns
38
+ * the best each track is licensed for, so there is no per-quality retry. The
39
+ * result has one entry per input track, in order; `null` for a track that is
40
+ * geo-blocked, unavailable, or errored.
41
+ *
42
+ * @param tracks from `getTrackInfo` / `parseInfo` (needs `TRACK_TOKEN`, `SNG_ID`, `FILESIZE_*`)
43
+ * @param qualities preference order — 9 = FLAC, 3 = MP3 320, 1 = MP3 128
44
+ */
45
+ export declare const resolveDownloadUrls: (tracks: trackType[], qualities?: number[]) => Promise<(ResolvedUrl | null)[]>;
@@ -3,7 +3,8 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.getTrackDownloadUrl = exports.ExpiredTrackToken = exports.GeoBlocked = exports.WrongLicense = void 0;
6
+ exports.resolveDownloadUrls = exports.getTrackDownloadUrl = exports.formatName = exports.ExpiredTrackToken = exports.GeoBlocked = exports.WrongLicense = void 0;
7
+ const delay_1 = __importDefault(require("delay"));
7
8
  const decrypt_1 = require("../lib/decrypt");
8
9
  const http_1 = require("../lib/http");
9
10
  const request_1 = __importDefault(require("../lib/request"));
@@ -64,36 +65,69 @@ const dzAuthenticate = async () => {
64
65
  };
65
66
  return user_data;
66
67
  };
68
+ const MEDIA_MAX_RETRIES = 3;
69
+ /** quality code -> the `format` string the media API expects */
70
+ const formatName = (quality) => {
71
+ switch (quality) {
72
+ case 9:
73
+ return 'FLAC';
74
+ case 3:
75
+ return 'MP3_320';
76
+ case 1:
77
+ return 'MP3_128';
78
+ default:
79
+ throw new Error(`Unknown quality ${quality}`);
80
+ }
81
+ };
82
+ exports.formatName = formatName;
83
+ /** POST media.deezer.com/v1/get_url with re-auth + exponential-backoff retry on 403/429/5xx. */
84
+ const mediaGetUrl = async (track_tokens, formats, attempt = 0) => {
85
+ var _a;
86
+ const user = user_data ? user_data : await dzAuthenticate();
87
+ try {
88
+ const { data } = await request_1.default.post('https://media.deezer.com/v1/get_url', {
89
+ license_token: user.license_token,
90
+ media: [{ type: 'FULL', formats }],
91
+ track_tokens,
92
+ });
93
+ return { data: (_a = data.data) !== null && _a !== void 0 ? _a : [], country: user.country };
94
+ }
95
+ catch (err) {
96
+ const status = err instanceof http_1.HttpStatusError ? err.statusCode : 0;
97
+ if ((status === 403 || status === 429 || status >= 500) && attempt < MEDIA_MAX_RETRIES) {
98
+ user_data = null;
99
+ await (0, delay_1.default)(500 * 2 ** attempt + Math.floor(Math.random() * 250));
100
+ return mediaGetUrl(track_tokens, formats, attempt + 1);
101
+ }
102
+ throw err;
103
+ }
104
+ };
105
+ /** Parse one `data[i]` entry from a get_url response into a source URL (or null / throw). */
106
+ const parseMediaEntry = (entry, token, country) => {
107
+ var _a, _b;
108
+ if (entry === null || entry === void 0 ? void 0 : entry.errors) {
109
+ const { code } = entry.errors[0];
110
+ if (code === 2002)
111
+ throw new GeoBlocked(country);
112
+ if (code === 2000 || code === 2001)
113
+ throw new ExpiredTrackToken(token);
114
+ throw new Error(Object.entries(entry.errors[0]).join(', '));
115
+ }
116
+ const media = (_a = entry === null || entry === void 0 ? void 0 : entry.media) === null || _a === void 0 ? void 0 : _a[0];
117
+ if (!((_b = media === null || media === void 0 ? void 0 : media.sources) === null || _b === void 0 ? void 0 : _b.length))
118
+ return null;
119
+ return { url: media.sources[0].url, format: media.format };
120
+ };
67
121
  const getTrackUrlFromServer = async (track_token, format) => {
122
+ var _a, _b;
68
123
  const user = user_data ? user_data : await dzAuthenticate();
69
124
  if ((format === 'FLAC' && !user.can_stream_lossless) || (format === 'MP3_320' && !user.can_stream_hq)) {
70
125
  throw new WrongLicense(format);
71
126
  }
72
- const { data } = await request_1.default.post('https://media.deezer.com/v1/get_url', {
73
- license_token: user.license_token,
74
- media: [
75
- {
76
- type: 'FULL',
77
- formats: [{ format, cipher: 'BF_CBC_STRIPE' }],
78
- },
79
- ],
80
- track_tokens: [track_token],
81
- });
82
- if (data.data.length > 0) {
83
- if (data.data[0].errors) {
84
- const { code } = data.data[0].errors[0];
85
- if (code === 2002) {
86
- throw new GeoBlocked(user.country);
87
- }
88
- // 2000: invalid/expired token · 2001: token has no rights on this song
89
- if (code === 2000 || code === 2001) {
90
- throw new ExpiredTrackToken(track_token);
91
- }
92
- throw new Error(Object.entries(data.data[0].errors[0]).join(', '));
93
- }
94
- return data.data[0].media.length > 0 ? data.data[0].media[0].sources[0].url : null;
95
- }
96
- return null;
127
+ const { data, country } = await mediaGetUrl([track_token], [{ format, cipher: 'BF_CBC_STRIPE' }]);
128
+ if (!data.length)
129
+ return null;
130
+ return (_b = (_a = parseMediaEntry(data[0], track_token, country)) === null || _a === void 0 ? void 0 : _a.url) !== null && _b !== void 0 ? _b : null;
97
131
  };
98
132
  /**
99
133
  * @param track Track info json returned from `getTrackInfo`
@@ -103,20 +137,8 @@ const getTrackDownloadUrl = async (track, quality) => {
103
137
  let wrongLicense = null;
104
138
  let geoBlocked = null;
105
139
  let expiredToken = null;
106
- let formatName;
107
- switch (quality) {
108
- case 9:
109
- formatName = 'FLAC';
110
- break;
111
- case 3:
112
- formatName = 'MP3_320';
113
- break;
114
- case 1:
115
- formatName = 'MP3_128';
116
- break;
117
- default:
118
- throw new Error(`Unknown quality ${quality}`);
119
- }
140
+ let mediaBlocked = null;
141
+ const format = (0, exports.formatName)(quality);
120
142
  // Track tokens last ~1 hour. If it's already stale, skip the doomed media API
121
143
  // call and go straight to the token-free fallback below.
122
144
  const tokenStale = Boolean(track.TRACK_TOKEN_EXPIRE && track.TRACK_TOKEN_EXPIRE * 1000 < Date.now());
@@ -126,7 +148,7 @@ const getTrackDownloadUrl = async (track, quality) => {
126
148
  else {
127
149
  // Get URL with the official API
128
150
  try {
129
- const url = await getTrackUrlFromServer(track.TRACK_TOKEN, formatName);
151
+ const url = await getTrackUrlFromServer(track.TRACK_TOKEN, format);
130
152
  if (url) {
131
153
  return {
132
154
  trackUrl: url,
@@ -145,6 +167,10 @@ const getTrackDownloadUrl = async (track, quality) => {
145
167
  else if (err instanceof ExpiredTrackToken) {
146
168
  expiredToken = err;
147
169
  }
170
+ else if (err instanceof http_1.HttpStatusError && (err.statusCode === 403 || err.statusCode === 429)) {
171
+ // media API is throttling this account — try the token-free legacy CDN below
172
+ mediaBlocked = err;
173
+ }
148
174
  else {
149
175
  throw err;
150
176
  }
@@ -172,6 +198,9 @@ const getTrackDownloadUrl = async (track, quality) => {
172
198
  if (expiredToken) {
173
199
  throw expiredToken;
174
200
  }
201
+ if (mediaBlocked) {
202
+ throw mediaBlocked;
203
+ }
175
204
  return null;
176
205
  };
177
206
  exports.getTrackDownloadUrl = getTrackDownloadUrl;
@@ -184,3 +213,42 @@ const testUrl = async (url) => {
184
213
  return 0;
185
214
  }
186
215
  };
216
+ const QUALITY_OF_FORMAT = { FLAC: 9, MP3_320: 3, MP3_128: 1, MP3_256: 3, MP3_64: 1 };
217
+ /**
218
+ * Resolve download URLs for many tracks in a **single** `get_url` request.
219
+ *
220
+ * `qualities` is an ordered preference list (e.g. `[9, 3, 1]`): Deezer returns
221
+ * the best each track is licensed for, so there is no per-quality retry. The
222
+ * result has one entry per input track, in order; `null` for a track that is
223
+ * geo-blocked, unavailable, or errored.
224
+ *
225
+ * @param tracks from `getTrackInfo` / `parseInfo` (needs `TRACK_TOKEN`, `SNG_ID`, `FILESIZE_*`)
226
+ * @param qualities preference order — 9 = FLAC, 3 = MP3 320, 1 = MP3 128
227
+ */
228
+ const resolveDownloadUrls = async (tracks, qualities = [9, 3, 1]) => {
229
+ if (!tracks.length)
230
+ return [];
231
+ const formats = qualities.map((q) => ({ format: (0, exports.formatName)(q), cipher: 'BF_CBC_STRIPE' }));
232
+ const { data, country } = await mediaGetUrl(tracks.map((t) => t.TRACK_TOKEN), formats);
233
+ return tracks.map((track, i) => {
234
+ var _a;
235
+ let parsed;
236
+ try {
237
+ parsed = parseMediaEntry(data[i], track.TRACK_TOKEN, country);
238
+ }
239
+ catch {
240
+ // per-track error (geo-block, no rights, expired token) — skip this one
241
+ return null;
242
+ }
243
+ if (!parsed)
244
+ return null;
245
+ const q = (_a = QUALITY_OF_FORMAT[parsed.format]) !== null && _a !== void 0 ? _a : qualities[0];
246
+ return {
247
+ trackUrl: parsed.url,
248
+ isEncrypted: parsed.url.includes('/mobile/') || parsed.url.includes('/media/'),
249
+ fileSize: getTrackFileSize(track, q),
250
+ format: parsed.format,
251
+ };
252
+ });
253
+ };
254
+ exports.resolveDownloadUrls = resolveDownloadUrls;
@@ -1,6 +1,8 @@
1
1
  /// <reference types="node" />
2
2
  /// <reference types="node" />
3
- import { IncomingHttpHeaders } from 'http';
3
+ /// <reference types="node" />
4
+ import { Agent as HttpAgent, IncomingHttpHeaders } from 'http';
5
+ import { Agent as HttpsAgent } from 'https';
4
6
  type HttpMethod = 'GET' | 'POST' | 'HEAD';
5
7
  type ResponseType = 'buffer' | 'json' | 'text';
6
8
  type QueryValue = string | number | boolean | null | undefined;
@@ -22,6 +24,8 @@ interface RequestDescriptor {
22
24
  timeout: number;
23
25
  url: string;
24
26
  }
27
+ export declare const httpAgent: HttpAgent;
28
+ export declare const httpsAgent: HttpsAgent;
25
29
  export interface HttpResponse<T> {
26
30
  config: RequestDescriptor;
27
31
  data: T;
package/dist/lib/http.js CHANGED
@@ -1,11 +1,31 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.headRequest = exports.getText = exports.getJson = exports.getBuffer = exports.HttpClient = exports.HttpStatusError = void 0;
3
+ exports.headRequest = exports.getText = exports.getJson = exports.getBuffer = exports.HttpClient = exports.HttpStatusError = exports.httpsAgent = exports.httpAgent = void 0;
4
4
  const http_1 = require("http");
5
5
  const https_1 = require("https");
6
6
  const zlib_1 = require("zlib");
7
- const httpAgent = new http_1.Agent({ keepAlive: true });
8
- const httpsAgent = new https_1.Agent({ keepAlive: true });
7
+ /**
8
+ * Shared keep-alive connection pools. Every request gerdur-core makes — gateway,
9
+ * media API, CDN HEAD probes — reuses these, so a batch of calls to the same host
10
+ * rides one handful of TCP+TLS connections instead of a fresh handshake each time.
11
+ *
12
+ * `maxSockets` is bounded (not the Node default of `Infinity`): the converter fans
13
+ * out at concurrency 10–25, so 64 is generous headroom while still capping a
14
+ * pathological fan-out that would otherwise open hundreds of sockets to
15
+ * `api.deezer.com` and get the account rate-limited. `scheduling: 'lifo'` keeps
16
+ * the hottest socket warm. Downstream apps can import these and hand them to
17
+ * `got`/`undici` so downloads share the same pool.
18
+ */
19
+ const AGENT_OPTS = {
20
+ keepAlive: true,
21
+ keepAliveMsecs: 30000,
22
+ maxSockets: 64,
23
+ maxFreeSockets: 16,
24
+ scheduling: 'lifo',
25
+ timeout: 60000,
26
+ };
27
+ exports.httpAgent = new http_1.Agent(AGENT_OPTS);
28
+ exports.httpsAgent = new https_1.Agent(AGENT_OPTS);
9
29
  class HttpStatusError extends Error {
10
30
  constructor(statusCode, headers, body) {
11
31
  super(`Request failed with status code ${statusCode}`);
@@ -86,7 +106,7 @@ const requestRaw = async (config, redirectCount = 0) => {
86
106
  const isHttps = requestUrl.protocol === 'https:';
87
107
  const requestFn = isHttps ? https_1.request : http_1.request;
88
108
  const req = requestFn({
89
- agent: isHttps ? httpsAgent : httpAgent,
109
+ agent: isHttps ? exports.httpsAgent : exports.httpAgent,
90
110
  headers,
91
111
  hostname: requestUrl.hostname,
92
112
  method: config.method,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "gerdur-core",
3
- "version": "1.0.2",
3
+ "version": "1.0.4",
4
4
  "description": "Core module for gerdur.",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",