@ctrl/deluge 4.3.1 → 5.0.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.
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
- # deluge [![npm](https://img.shields.io/npm/v/@ctrl/deluge.svg?maxAge=3600)](https://www.npmjs.com/package/@ctrl/deluge) [![CircleCI](https://circleci.com/gh/scttcper/deluge.svg?style=svg)](https://circleci.com/gh/scttcper/deluge) [![coverage status](https://codecov.io/gh/scttcper/deluge/branch/master/graph/badge.svg)](https://codecov.io/gh/scttcper/deluge)
1
+ # deluge [![npm](https://img.shields.io/npm/v/@ctrl/deluge.svg?maxAge=3600)](https://www.npmjs.com/package/@ctrl/deluge) [![coverage status](https://codecov.io/gh/scttcper/deluge/branch/master/graph/badge.svg)](https://codecov.io/gh/scttcper/deluge)
2
2
 
3
- > TypeScript api wrapper for [deluge](https://deluge-torrent.org/) using [got](https://github.com/sindresorhus/got)
3
+ > TypeScript api wrapper for [deluge](https://deluge-torrent.org/) using [ofetch](https://github.com/unjs/ofetch)
4
4
 
5
5
  ### Install
6
6
 
@@ -75,3 +75,19 @@ transmission - https://github.com/scttcper/transmission
75
75
  qbittorrent - https://github.com/scttcper/qbittorrent
76
76
  utorrent - https://github.com/scttcper/utorrent
77
77
  rtorrent - https://github.com/scttcper/rtorrent
78
+
79
+ ### Start a test docker container
80
+
81
+ ```
82
+ docker run -d \
83
+ --name=deluge \
84
+ -e PUID=1000 \
85
+ -e PGID=1000 \
86
+ -e TZ=Etc/UTC \
87
+ -e DELUGE_LOGLEVEL=error `#optional` \
88
+ -p 8112:8112 \
89
+ -p 6881:6881 \
90
+ -p 6881:6881/udp \
91
+ --restart unless-stopped \
92
+ lscr.io/linuxserver/deluge:latest
93
+ ```
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" resolution-mode="require"/>
2
- import type { Response } from 'got';
2
+ import { FetchResponse } from 'ofetch';
3
3
  import type { AddTorrentOptions as NormalizedAddTorrentOptions, AllClientData, NormalizedTorrent, TorrentClient, TorrentSettings } from '@ctrl/shared-torrent';
4
4
  import type { AddTorrentOptions, AddTorrentResponse, BooleanStatus, ConfigResponse, DefaultResponse, DelugeSettings, GetHostsResponse, GetHostStatusResponse, ListMethods, PluginInfo, PluginsListResponse, StringStatus, TorrentFiles, TorrentInfo, TorrentListResponse, TorrentOptions, TorrentStatus, Tracker, UploadResponse } from './types.js';
5
5
  export declare class Deluge implements TorrentClient {
@@ -106,7 +106,6 @@ export declare class Deluge implements TorrentClient {
106
106
  getPluginInfo(plugins: string[]): Promise<PluginInfo>;
107
107
  enablePlugin(plugins: string[]): Promise<DefaultResponse>;
108
108
  disablePlugin(plugins: string[]): Promise<DefaultResponse>;
109
- request<T extends object>(method: string, params?: any[], needsAuth?: boolean, autoConnect?: boolean): Promise<Response<T>>;
110
- private _normalizeTorrentData;
109
+ request<T extends object>(method: string, params?: any[], needsAuth?: boolean, autoConnect?: boolean): Promise<FetchResponse<T>>;
111
110
  private _validateAuth;
112
111
  }
@@ -1,11 +1,9 @@
1
- import { existsSync } from 'fs';
2
- import { File, FormData } from 'formdata-node';
3
- import { fileFromPath } from 'formdata-node/file-from-path';
4
- import got from 'got';
1
+ import { FormData } from 'node-fetch-native';
2
+ import { ofetch } from 'ofetch';
5
3
  import { Cookie } from 'tough-cookie';
4
+ import { joinURL } from 'ufo';
6
5
  import { magnetDecode } from '@ctrl/magnet-link';
7
- import { TorrentState } from '@ctrl/shared-torrent';
8
- import { urlJoin } from '@ctrl/url-join';
6
+ import { normalizeTorrentData } from './normalizeTorrentData.js';
9
7
  const defaults = {
10
8
  baseUrl: 'http://localhost:8112/',
11
9
  path: '/json',
@@ -13,25 +11,10 @@ const defaults = {
13
11
  timeout: 5000,
14
12
  };
15
13
  export class Deluge {
14
+ config;
15
+ _msgId = 0;
16
+ _cookie;
16
17
  constructor(options = {}) {
17
- Object.defineProperty(this, "config", {
18
- enumerable: true,
19
- configurable: true,
20
- writable: true,
21
- value: void 0
22
- });
23
- Object.defineProperty(this, "_msgId", {
24
- enumerable: true,
25
- configurable: true,
26
- writable: true,
27
- value: 0
28
- });
29
- Object.defineProperty(this, "_cookie", {
30
- enumerable: true,
31
- configurable: true,
32
- writable: true,
33
- value: void 0
34
- });
35
18
  this.config = { ...defaults, ...options };
36
19
  }
37
20
  resetSession() {
@@ -40,7 +23,7 @@ export class Deluge {
40
23
  }
41
24
  async getHosts() {
42
25
  const res = await this.request('web.get_hosts', [], true, false);
43
- return res.body;
26
+ return res._data;
44
27
  }
45
28
  /**
46
29
  * Gets host status
@@ -48,7 +31,7 @@ export class Deluge {
48
31
  */
49
32
  async getHostStatus(host) {
50
33
  const res = await this.request('web.get_host_status', [host], true, false);
51
- return res.body;
34
+ return res._data;
52
35
  }
53
36
  /**
54
37
  * Connects deluge and returns a list of available methods
@@ -65,11 +48,11 @@ export class Deluge {
65
48
  throw new Error('No hosts found');
66
49
  }
67
50
  const res = await this.request('web.connect', [host], true, false);
68
- return res.body;
51
+ return res._data;
69
52
  }
70
53
  async connected() {
71
54
  const res = await this.request('web.connected', [], true, false);
72
- return res.body.result;
55
+ return res._data.result;
73
56
  }
74
57
  /**
75
58
  * Disconnects deluge - warning all instances connected to this client will also be disconnected.
@@ -77,12 +60,13 @@ export class Deluge {
77
60
  */
78
61
  async disconnect() {
79
62
  const res = await this.request('web.disconnect', [], true, false);
63
+ const body = res._data;
80
64
  // deluge 1.x returns a boolean and 2.x returns a string
81
- if (typeof res.body.result === 'boolean') {
82
- return res.body.result;
65
+ if (typeof body.result === 'boolean') {
66
+ return body.result;
83
67
  }
84
68
  // "Connection was closed cleanly."
85
- return res.body.result.includes('closed cleanly');
69
+ return body.result.includes('closed cleanly');
86
70
  }
87
71
  /**
88
72
  * Checks current session is valid
@@ -101,7 +85,8 @@ export class Deluge {
101
85
  if (this._cookie) {
102
86
  try {
103
87
  const check = await this.request('auth.check_session', undefined, false);
104
- if (check?.body?.result) {
88
+ const body = await check.json();
89
+ if (body?.result) {
105
90
  return true;
106
91
  }
107
92
  }
@@ -119,10 +104,10 @@ export class Deluge {
119
104
  async login() {
120
105
  this.resetSession();
121
106
  const res = await this.request('auth.login', [this.config.password], false);
122
- if (!res.body.result || !res.headers || !res.headers['set-cookie']) {
107
+ if (!res.ok || !res.headers?.get('set-cookie')?.length) {
123
108
  throw new Error('Auth failed, incorrect password');
124
109
  }
125
- this._cookie = Cookie.parse(res.headers['set-cookie'][0]);
110
+ this._cookie = Cookie.parse(res.headers.get('set-cookie'));
126
111
  return true;
127
112
  }
128
113
  /**
@@ -131,15 +116,16 @@ export class Deluge {
131
116
  */
132
117
  async logout() {
133
118
  const res = await this.request('auth.delete_session');
119
+ const body = res._data;
134
120
  this.resetSession();
135
- return res.body.result;
121
+ return body.result;
136
122
  }
137
123
  /**
138
124
  * returns the version ex - `2.0.3-2-201906121747-ubuntu18.04.1`
139
125
  */
140
126
  async getVersion() {
141
127
  const req = await this.request('daemon.get_version');
142
- return req.body;
128
+ return req._data;
143
129
  }
144
130
  /**
145
131
  * used to get torrent info before adding
@@ -147,7 +133,7 @@ export class Deluge {
147
133
  */
148
134
  async getTorrentInfo(tmpPath) {
149
135
  const res = await this.request('web.get_torrent_info', [tmpPath]);
150
- return res.body;
136
+ return res._data;
151
137
  }
152
138
  /**
153
139
  * Lists methods
@@ -156,7 +142,7 @@ export class Deluge {
156
142
  */
157
143
  async listMethods(auth = true) {
158
144
  const req = await this.request('system.listMethods', undefined, auth);
159
- return req.body;
145
+ return req._data;
160
146
  }
161
147
  async upload(torrent) {
162
148
  await this._validateAuth();
@@ -167,28 +153,23 @@ export class Deluge {
167
153
  const form = new FormData();
168
154
  const type = { type: 'application/x-bittorrent' };
169
155
  if (typeof torrent === 'string') {
170
- if (existsSync(torrent)) {
171
- const file = await fileFromPath(torrent, 'temp.torrent', type);
172
- form.set('file', file);
173
- }
174
- else {
175
- form.set('file', new File([Buffer.from(torrent, 'base64')], 'file.torrent', type));
176
- }
156
+ form.set('file', new File([Buffer.from(torrent, 'base64')], 'file.torrent', type));
177
157
  }
178
158
  else {
179
159
  const file = new File([torrent], 'torrent', type);
180
160
  form.set('file', file);
181
161
  }
182
- const url = urlJoin(this.config.baseUrl, '/upload');
183
- const res = await got.post(url, {
162
+ const url = joinURL(this.config.baseUrl, '/upload');
163
+ const res = await ofetch(url, {
164
+ method: 'POST',
184
165
  body: form,
185
- retry: { limit: 0 },
186
- timeout: { request: this.config.timeout },
187
- // allow proxy agent
188
- ...(this.config.agent ? { agent: this.config.agent } : {}),
166
+ retry: 0,
167
+ timeout: this.config.timeout,
168
+ parseResponse: JSON.parse,
169
+ // @ts-expect-error for some reason agent is not in the type
170
+ agent: this.config.agent,
189
171
  });
190
- // repsonse is json but in a string, cannot use native got.json()
191
- return JSON.parse(res.body);
172
+ return res;
192
173
  }
193
174
  /**
194
175
  * Download a torrent from url, pass the result to {@link Deluge.addTorrent}
@@ -198,10 +179,11 @@ export class Deluge {
198
179
  */
199
180
  async downloadFromUrl(url, cookies = '') {
200
181
  const res = await this.request('web.download_torrent_from_url', [url, cookies]);
201
- if (!res.body.result) {
182
+ const body = res._data;
183
+ if (!body.result) {
202
184
  throw new Error('Failed to download torrent');
203
185
  }
204
- return res.body.result;
186
+ return body.result;
205
187
  }
206
188
  async addTorrent(torrent, config = {}) {
207
189
  let path;
@@ -236,10 +218,11 @@ export class Deluge {
236
218
  ...config,
237
219
  };
238
220
  const res = await this.request('web.add_torrents', [[{ path, options }]]);
239
- if (!res.body.result) {
221
+ const body = res._data;
222
+ if (!body.result) {
240
223
  throw new Error('Failed to add torrent');
241
224
  }
242
- return res.body;
225
+ return body;
243
226
  }
244
227
  async normalizedAddTorrent(torrent, options = {}) {
245
228
  const torrentOptions = {};
@@ -289,7 +272,7 @@ export class Deluge {
289
272
  ...config,
290
273
  };
291
274
  const res = await this.request('core.add_torrent_magnet', [magnet, options]);
292
- return res.body;
275
+ return res._data;
293
276
  }
294
277
  /**
295
278
  *
@@ -298,20 +281,21 @@ export class Deluge {
298
281
  */
299
282
  async removeTorrent(torrentId, removeData = true) {
300
283
  const req = await this.request('core.remove_torrent', [torrentId, removeData]);
301
- return req.body;
284
+ return req._data;
302
285
  }
303
286
  async changePassword(password) {
304
287
  const res = await this.request('auth.change_password', [
305
288
  this.config.password,
306
289
  password,
307
290
  ]);
308
- if (!res.body.result || !res.headers || !res.headers['set-cookie']) {
291
+ const body = res._data;
292
+ if (!body.result || !res.headers.get('set-cookie')?.length) {
309
293
  throw new Error('Old password incorrect');
310
294
  }
311
295
  // update current password to new password
312
296
  this.config.password = password;
313
- this._cookie = Cookie.parse(res.headers['set-cookie'][0]);
314
- return res.body;
297
+ this._cookie = Cookie.parse(res.headers.get('set-cookie'));
298
+ return body;
315
299
  }
316
300
  async getAllData() {
317
301
  const listTorrents = await this.listTorrents();
@@ -322,7 +306,7 @@ export class Deluge {
322
306
  };
323
307
  for (const id of Object.keys(listTorrents.result.torrents)) {
324
308
  const torrent = listTorrents.result.torrents[id];
325
- const torrentData = this._normalizeTorrentData(id, torrent);
309
+ const torrentData = normalizeTorrentData(id, torrent);
326
310
  results.torrents.push(torrentData);
327
311
  }
328
312
  if (listTorrents.result.filters.label) {
@@ -369,11 +353,11 @@ export class Deluge {
369
353
  [...new Set(fields)],
370
354
  filter,
371
355
  ]);
372
- return req.body;
356
+ return req._data;
373
357
  }
374
358
  async getTorrent(id) {
375
359
  const torrentResponse = await this.getTorrentStatus(id);
376
- return this._normalizeTorrentData(id, torrentResponse.result);
360
+ return normalizeTorrentData(id, torrentResponse.result);
377
361
  }
378
362
  /**
379
363
  * get torrent state/status
@@ -424,103 +408,104 @@ export class Deluge {
424
408
  ...additionalFields,
425
409
  ];
426
410
  const req = await this.request('web.get_torrent_status', [torrentId, fields]);
427
- if (!req.body.result || !Object.keys(req.body.result).length) {
411
+ const body = req._data;
412
+ if (!body.result || !Object.keys(body.result).length) {
428
413
  throw new Error('Torrent not found');
429
414
  }
430
- return req.body;
415
+ return body;
431
416
  }
432
417
  /**
433
418
  * Get list of files for a torrent
434
419
  */
435
420
  async getTorrentFiles(torrentId) {
436
421
  const req = await this.request('web.get_torrent_files', [torrentId]);
437
- return req.body;
422
+ return req._data;
438
423
  }
439
424
  async pauseTorrent(torrentId) {
440
425
  const req = await this.request('core.pause_torrent', [[torrentId]]);
441
- return req.body;
426
+ return req._data;
442
427
  }
443
428
  async resumeTorrent(torrentId) {
444
429
  const req = await this.request('core.resume_torrent', [[torrentId]]);
445
- return req.body;
430
+ return req._data;
446
431
  }
447
432
  async setTorrentOptions(torrentId, options = {}) {
448
433
  const req = await this.request('core.set_torrent_options', [
449
434
  [torrentId],
450
435
  options,
451
436
  ]);
452
- return req.body;
437
+ return req._data;
453
438
  }
454
439
  async setTorrentTrackers(torrentId, trackers = []) {
455
440
  const req = await this.request('core.set_torrent_trackers', [
456
441
  [torrentId],
457
442
  trackers,
458
443
  ]);
459
- return req.body;
444
+ return req._data;
460
445
  }
461
446
  async updateTorrentTrackers(torrentId) {
462
447
  const req = await this.request('core.force_reannounce', [[torrentId]]);
463
- return req.body;
448
+ return req._data;
464
449
  }
465
450
  async verifyTorrent(torrentId) {
466
451
  const req = await this.request('core.force_recheck', [[torrentId]]);
467
- return req.body;
452
+ return req._data;
468
453
  }
469
454
  async setTorrentLabel(torrentId, label) {
470
455
  const req = await this.request('label.set_torrent', [torrentId, label]);
471
- return req.body;
456
+ return req._data;
472
457
  }
473
458
  async addLabel(label) {
474
459
  const req = await this.request('label.add', [label]);
475
- return req.body;
460
+ return req._data;
476
461
  }
477
462
  async removeLabel(label) {
478
463
  const req = await this.request('label.remove', [label]);
479
- return req.body;
464
+ return req._data;
480
465
  }
481
466
  async getLabels() {
482
467
  const req = await this.request('label.get_labels', []);
483
- return req.body;
468
+ return req._data;
484
469
  }
485
470
  async queueTop(torrentId) {
486
471
  const req = await this.request('core.queue_top', [[torrentId]]);
487
- return req.body;
472
+ return req._data;
488
473
  }
489
474
  async queueBottom(torrentId) {
490
475
  const req = await this.request('core.queue_bottom', [[torrentId]]);
491
- return req.body;
476
+ return req._data;
492
477
  }
493
478
  async queueUp(torrentId) {
494
479
  const req = await this.request('core.queue_up', [[torrentId]]);
495
- return req.body;
480
+ return req._data;
496
481
  }
497
482
  async queueDown(torrentId) {
498
483
  const req = await this.request('core.queue_down', [[torrentId]]);
499
- return req.body;
484
+ return req._data;
500
485
  }
501
486
  async getConfig() {
502
487
  const req = await this.request('core.get_config', []);
503
- return req.body;
488
+ return req._data;
504
489
  }
505
490
  async setConfig(config) {
506
491
  const req = await this.request('core.set_config', [config]);
507
- return req.body;
492
+ return req._data;
508
493
  }
509
494
  async getPlugins() {
510
495
  const req = await this.request('web.get_plugins', []);
511
- return req.body;
496
+ return req._data;
512
497
  }
513
498
  async getPluginInfo(plugins) {
514
499
  const req = await this.request('web.get_plugin_info', plugins);
515
- return req.body;
500
+ return req._data;
516
501
  }
517
502
  async enablePlugin(plugins) {
518
503
  const req = await this.request('core.enable_plugin', plugins);
519
- return req.body;
504
+ return req._data;
520
505
  }
521
506
  async disablePlugin(plugins) {
522
507
  const req = await this.request('core.disable_plugin', plugins);
523
- return req.body;
508
+ return req._data;
524
509
  }
525
510
  // eslint-disable-next-line @typescript-eslint/ban-types
526
511
  async request(method, params = [], needsAuth = true, autoConnect = true) {
@@ -539,19 +524,21 @@ export class Deluge {
539
524
  const headers = {
540
525
  Cookie: this._cookie?.cookieString?.(),
541
526
  };
542
- const url = urlJoin(this.config.baseUrl, this.config.path);
543
- const res = await got.post(url, {
544
- json: {
527
+ const url = joinURL(this.config.baseUrl, this.config.path);
528
+ const res = await ofetch.raw(url, {
529
+ method: 'POST',
530
+ body: JSON.stringify({
545
531
  method,
546
532
  params,
547
533
  id: this._msgId++,
548
- },
534
+ }),
549
535
  headers,
550
- retry: { limit: 0 },
551
- timeout: { request: this.config.timeout },
536
+ retry: 0,
537
+ timeout: this.config.timeout,
552
538
  responseType: 'json',
553
- // allow proxy agent
554
- ...(this.config.agent ? { agent: this.config.agent } : {}),
539
+ parseResponse: JSON.parse,
540
+ // @ts-expect-error for some reason agent is not in the type
541
+ agent: this.config.agent,
555
542
  });
556
543
  const err = res.body?.error ?? (typeof res.body === 'string' && res.body);
557
544
  if (err) {
@@ -559,42 +546,6 @@ export class Deluge {
559
546
  }
560
547
  return res;
561
548
  }
562
- _normalizeTorrentData(id, torrent) {
563
- const dateAdded = new Date(torrent.time_added * 1000).toISOString();
564
- // normalize state to enum
565
- let state = TorrentState.unknown;
566
- if (Object.keys(TorrentState).includes(torrent.state.toLowerCase())) {
567
- state = TorrentState[torrent.state.toLowerCase()];
568
- }
569
- const isCompleted = torrent.progress >= 100;
570
- const result = {
571
- id,
572
- name: torrent.name,
573
- state,
574
- isCompleted,
575
- stateMessage: torrent.state,
576
- progress: torrent.progress / 100,
577
- ratio: torrent.ratio,
578
- dateAdded,
579
- dateCompleted: undefined,
580
- label: torrent.label,
581
- savePath: torrent.save_path,
582
- uploadSpeed: torrent.upload_payload_rate,
583
- downloadSpeed: torrent.download_payload_rate,
584
- eta: torrent.eta,
585
- queuePosition: torrent.queue + 1,
586
- connectedPeers: torrent.num_peers,
587
- connectedSeeds: torrent.num_seeds,
588
- totalPeers: torrent.total_peers,
589
- totalSeeds: torrent.total_seeds,
590
- totalSelected: torrent.total_wanted,
591
- totalSize: torrent.total_size,
592
- totalUploaded: torrent.total_uploaded,
593
- totalDownloaded: torrent.total_done,
594
- raw: torrent,
595
- };
596
- return result;
597
- }
598
549
  async _validateAuth() {
599
550
  let validAuth = await this.checkSession();
600
551
  if (!validAuth) {
@@ -0,0 +1,3 @@
1
+ import { NormalizedTorrent } from '@ctrl/shared-torrent';
2
+ import { Torrent } from './types.js';
3
+ export declare function normalizeTorrentData(id: string, torrent: Torrent): NormalizedTorrent;
@@ -0,0 +1,37 @@
1
+ import { TorrentState } from '@ctrl/shared-torrent';
2
+ export function normalizeTorrentData(id, torrent) {
3
+ const dateAdded = new Date(torrent.time_added * 1000).toISOString();
4
+ // normalize state to enum
5
+ let state = TorrentState.unknown;
6
+ if (Object.keys(TorrentState).includes(torrent.state.toLowerCase())) {
7
+ state = TorrentState[torrent.state.toLowerCase()];
8
+ }
9
+ const isCompleted = torrent.progress >= 100;
10
+ const result = {
11
+ id,
12
+ name: torrent.name,
13
+ state,
14
+ isCompleted,
15
+ stateMessage: torrent.state,
16
+ progress: torrent.progress / 100,
17
+ ratio: torrent.ratio,
18
+ dateAdded,
19
+ dateCompleted: undefined,
20
+ label: torrent.label,
21
+ savePath: torrent.save_path,
22
+ uploadSpeed: torrent.upload_payload_rate,
23
+ downloadSpeed: torrent.download_payload_rate,
24
+ eta: torrent.eta,
25
+ queuePosition: torrent.queue + 1,
26
+ connectedPeers: torrent.num_peers,
27
+ connectedSeeds: torrent.num_seeds,
28
+ totalPeers: torrent.total_peers,
29
+ totalSeeds: torrent.total_seeds,
30
+ totalSelected: torrent.total_wanted,
31
+ totalSize: torrent.total_size,
32
+ totalUploaded: torrent.total_uploaded,
33
+ totalDownloaded: torrent.total_done,
34
+ raw: torrent,
35
+ };
36
+ return result;
37
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ctrl/deluge",
3
- "version": "4.3.1",
3
+ "version": "5.0.1",
4
4
  "description": "TypeScript api wrapper for deluge using got",
5
5
  "author": "Scott Cooper <scttcper@gmail.com>",
6
6
  "license": "MIT",
@@ -28,27 +28,27 @@
28
28
  "test:ci": "vitest run --coverage --reporter=default --reporter=junit --outputFile=./junit.xml"
29
29
  },
30
30
  "dependencies": {
31
- "@ctrl/magnet-link": "^3.1.1",
32
- "@ctrl/shared-torrent": "^4.3.2",
33
- "@ctrl/url-join": "^2.0.2",
34
- "formdata-node": "^5.0.0",
35
- "got": "^12.6.0",
36
- "tough-cookie": "^4.1.2"
31
+ "@ctrl/magnet-link": "^3.1.2",
32
+ "@ctrl/shared-torrent": "^5.0.0",
33
+ "node-fetch-native": "^1.4.1",
34
+ "ofetch": "^1.3.3",
35
+ "tough-cookie": "^4.1.3",
36
+ "ufo": "^1.3.1"
37
37
  },
38
38
  "devDependencies": {
39
- "@ctrl/eslint-config": "3.6.2",
40
- "@sindresorhus/tsconfig": "3.0.1",
41
- "@types/node": "18.15.0",
42
- "@types/tough-cookie": "4.0.2",
43
- "@vitest/coverage-c8": "0.29.2",
44
- "c8": "7.13.0",
45
- "p-wait-for": "5.0.0",
46
- "typedoc": "0.23.26",
47
- "typescript": "4.9.5",
48
- "vitest": "0.29.2"
39
+ "@ctrl/eslint-config": "4.0.9",
40
+ "@sindresorhus/tsconfig": "5.0.0",
41
+ "@types/node": "20.8.10",
42
+ "@types/tough-cookie": "4.0.4",
43
+ "@vitest/coverage-v8": "0.34.6",
44
+ "p-wait-for": "5.0.2",
45
+ "typedoc": "0.25.3",
46
+ "typescript": "5.2.2",
47
+ "vitest": "0.34.6"
49
48
  },
50
49
  "publishConfig": {
51
- "access": "public"
50
+ "access": "public",
51
+ "provenance": true
52
52
  },
53
53
  "release": {
54
54
  "branches": [
@@ -56,6 +56,6 @@
56
56
  ]
57
57
  },
58
58
  "engines": {
59
- "node": ">=14.16"
59
+ "node": ">=18"
60
60
  }
61
61
  }